Hi. Long time no see. But eventually find myself back here. Great community.
I was looking into building more complex UI:s in Maya using PySide2 or QML. What I’m looking for is to create something like this. Arbitrary shaped hitboxes.
Not really sure what he uses, but the type of things I’m interested in can be achieved in HTML. however I’m not sure if it is possible in Qt this way. There used to be HTML support in Maya, right? like back in v6? https://www.youtube.com/watch?v=prU2MYPMoiw
So I’m eager for anyones ideas or tips really.
Keep it up!
The QGraphicsScene is a special kind of widget which allows you to paint items on a canvas and define how they draw and what actions occur when you interact with them etc.
Essetially you create a graphics scene, then you add items to the scene. Those items could be simple circles, rectangles etc - or they could be custom items which draw they own shapes using paths or images. Because items are classes, you can then override the mouse events, the paint events and most other things too.
As you progress you can utilise script jobs to make the panel bi-directional too, for instance in that video he clicks an item in the panel and it selects the control in the rig, it can be a nice polish feature to have the panel update live as you select things in the scene as well
This is a very simple example of code:
That is doing the bare minimum to add something to the scene (the text item). Whilst this is a more thorough example:
Dont be put off by the amount of math in the second example, that can largely be ignored (because its creating a dynamic spring effect between the nodes). But it shows creating custom items and defining their draw behaviours etc.
Hope that helps a little - and please post any questions, we’re all more than happy to help!
Hi. I just got back into this after a long time.
I’ve tested the idea with using the html approach. loading in a svg file, but obviously I don’t know how I could execute Maya code from a html-file and inject it back into Maya. Also I’m not sure if there’s a way to actually have a selection dragger functionality, selecting many islands at once. I was just inspired by the old tutorial about the html view that used to work with Maya. https://imgur.com/9rXmha0
So I’ve started looking into using the QGraphicsScene because I’m sure it could do exactly what I want. I’ve found some resources that got me started. Namely this one. https://discourse.techart.online/t/pyqt-button-click-area-non-rectangular-area/5705
And here’s an example. I can upload the images I used, otherwise I got one online which i’m using for both the image and the mask. It works, but comes out with some artefacts.
However I’m looking to have many masks to split up a character in segments and I’m not entirely sure how to do it. I then found this link: https://www.codetd.com/en/article/10005227
and this is precisely what I would like to do. paint different region masks to act as buttons. I’m sure it’s possible to implement selection dragging over multiple buttons too.
So I’ve been working on this and trying to add a rect drag selection. Now I’m stuck at getting said selection to only select the parts where I have painted masks. Unfortunately it sees the QLabelButton, not filtering to its mask and because the QLabelButton is as big as the window, it will always be selected no matter where I drag and release.
I’ve posted on stack overflow too. If this is an illegal cross-post I’ll delete it. But I could use any help or ideas.
from maya import OpenMayaUI
import pymel.core as pm
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtGui import QPixmap, QIcon
from shiboken2 import wrapInstance
import urllib
class QLabelButton(QtWidgets.QLabel):
def mouseReleaseEvent(self, ev):
self.emit(QtCore.SIGNAL('clicked()'))
def main_maya_window():
main_window_ptr = OpenMayaUI.MQtUtil.mainWindow()
return wrapInstance(long(main_window_ptr), QtWidgets.QWidget)
class rubberBandUI(QtWidgets.QDialog):
def __init__(self, parent=main_maya_window()):
super(rubberBandUI, self).__init__(parent)
imgRes = [512, 512]
self.setMinimumSize(imgRes[0], imgRes[1])
self.setMaximumSize(imgRes[0], imgRes[1])
# resources
bgPath = r"C://bg.png"
maskPath = r"C://bg_mask.png"
# background image
self.bg = QtWidgets.QLabel('bg', self)
self.bg.setPixmap(QtGui.QPixmap(bgPath))
# mask image
self.mask = QLabelButton('mask', self)
self.mask.setGeometry(0, 0, imgRes[0], imgRes[1])
self.mask.setAlignment(QtCore.Qt.AlignCenter)
self.mask.setMask(maskPath)
self.connect(self.mask, QtCore.SIGNAL('clicked()'), lambda: self.onClick(self.mask) )
self.mask.setStyleSheet("""QLabel:hover{background-color: rgba(64, 128, 255, 180); border: 1px solid blue;}""")
# create rubber band selection
self.rubberBand = QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle, self)
# Create variables that will be handling the moving logic.
self.sourceGeo = None
self.altPoint = None
self.delta = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.origin = event.pos()
self.drag_selection = QtCore.QRect(self.origin, QtCore.QSize())
self.rubberBand.setGeometry(self.drag_selection)
self.rubberBand.show()
# Must implement this event to detect when alt gets released
def keyReleaseEvent(self, event):
if event.key() == QtCore.Qt.Key_Alt:
if self.delta is not None:
# This is important: Add delta to origin so that it shifts it over.
# This is needed if the user repeatedly pressed alt to move it, otherwise it would pop.
self.origin += self.delta
# Reset the rest of the variables.
self.sourceGeo = None
self.altPoint = None
self.delta = None
def mouseMoveEvent(self, event):
if event.modifiers() == QtCore.Qt.AltModifier:
# Get the point where alt is pressed and the selection's current geometry.
if self.altPoint is None:
self.sourceGeo = self.rubberBand.geometry()
self.altPoint = event.pos()
self.delta = event.pos() - self.altPoint # Calculate difference from the point alt was pressed to where the cursor is now.
newGeo = QtCore.QRect(self.sourceGeo) # Create a copy
newGeo.moveTopLeft(self.sourceGeo.topLeft() + self.delta) # Apply the delta onto the geometry to move it.
self.rubberBand.setGeometry(newGeo) # Move the selection!
else:
self.drag_selection = QtCore.QRect(self.origin, event.pos()).normalized()
self.rubberBand.setGeometry(self.drag_selection)
def mouseReleaseEvent(self, event):
if self.rubberBand.isVisible():
self.rubberBand.hide()
selected = []
rect = self.rubberBand.geometry()
#self.cropImage(rect)
for child in self.findChildren(QLabelButton):
if rect.intersects(child.geometry()):
selected.append(child)
print 'Selection Contains:\n ',
if selected:
print ' '.join(
'Button: %s\n' % child.text() for child in selected)
else:
print ' Nothing\n'
# label click function to print its name
def onClick(self, button):
print '%s clicked' % button.text()
if __name__ == '__main__':
app = QtWidgets.QApplication.instance()
if app == None:
app = QtWidgets.QApplication([])
win = rubberBandUI()
#Set WA_DeleteOnClose attribute
win.setAttribute(QtCore.Qt.WA_DeleteOnClose)
win.show()
app.exec_()
sys.exit()