Drag n Drop Button und Dropdown-Menü PyQt / Qt designer
Ich möchte die "Best Practice" kennen, mit der das Verhalten einiger Schaltflächen folgendermaßen geändert werden kann:
Ich möchte mit einem Klick ein Menü erscheinen lassen. Wenn Sie dieselbe Schaltfläche ziehen, können Sie sie auch in eine andere ziehen, um eine Linie zu zeichnen, die sie verbindet.
Hier ist ein Beispiel: Die Idee ist, diese "Jack" -Tasten mit anderen "Input" -Tasten zu verbinden.
Ich habe den Qt-Designer verwendet und festgestellt, dass in den Schaltflächeneigenschaften nur die Eigenschaft "acceptDrops" aufgeführt ist, aber ich kann sie nicht zum Laufen bringen. Signale / Slots enthalten keine Informationen zum Ziehen oder Ablegen.
So denke ich, dass der einzige Weg, dies zu tun, das Erstellen eines "benutzerdefinierten Widgets" oder das "Neuimplementieren" einer Schaltfläche durch Code ist. Vielleicht dasselbe mit Signals / Slots
Was ist die beste Vorgehensweise, wenn ich die von pyuic generierte Datei nicht ändern möchte?
AKTUALISIERE: Der Ansatz, den ich ausprobiert habe, ist die Verwendung von Qt Designer und der Option "Heraufgestufte Widgets". Dadurch kann ich separate Klassendateien erstellen und einige Elemente neu implementieren. Ich habe bereits getestet, indem ich einen PushButton zu einem "DragButton" hochgestuft habe und eine Klasse dafür erstellt habe:
von PyQt4 importieren QtGui, QtCore
class DragButton (QtGui.QPushButton):
def __init__(self, parent):
super(DragButton, self).__init__(parent)
self.allowDrag = True
def setAllowDrag(self, allowDrag):
if type(allowDrag) == bool:
self.allowDrag = allowDrag
else:
raise TypeError("You have to set a boolean type")
def mouseMoveEvent(self, e):
if e.buttons() != QtCore.Qt.RightButton:
return
if self.allowDrag == True:
# write the relative cursor position to mime data
mimeData = QtCore.QMimeData()
# simple string with 'x,y'
mimeData.setText('%d,%d' % (e.x(), e.y()))
print mimeData.text()
# let's make it fancy. we'll show a "ghost" of the button as we drag
# grab the button to a pixmap
pixmap = QtGui.QPixmap.grabWidget(self)
# below makes the pixmap half transparent
painter = QtGui.QPainter(pixmap)
painter.setCompositionMode(painter.CompositionMode_DestinationIn)
painter.fillRect(pixmap.rect(), QtGui.QColor(0, 0, 0, 127))
painter.end()
# make a QDrag
drag = QtGui.QDrag(self)
# put our MimeData
drag.setMimeData(mimeData)
# set its Pixmap
drag.setPixmap(pixmap)
# shift the Pixmap so that it coincides with the cursor position
drag.setHotSpot(e.pos())
# start the drag operation
# exec_ will return the accepted action from dropEvent
if drag.exec_(QtCore.Qt.LinkAction | QtCore.Qt.MoveAction) == QtCore.Qt.LinkAction:
print 'linked'
else:
print 'moved'
def mousePressEvent(self, e):
QtGui.QPushButton.mousePressEvent(self, e)
if e.button() == QtCore.Qt.LeftButton:
print 'press'
#AQUI DEBO IMPLEMENTAR EL MENU CONTEXTUAL
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
# get the relative position from the mime data
mime = e.mimeData().text()
x, y = map(int, mime.split(','))
# move
# so move the dragged button (i.e. event.source())
print e.pos()
#e.source().move(e.pos()-QtCore.QPoint(x, y))
# set the drop action as LinkAction
e.setDropAction(QtCore.Qt.LinkAction)
# tell the QDrag we accepted it
e.accept()
Ich habe einige Tipps und Schnipsel aus diesem Beitrag: PyQt4 - Ziehen und Ablegen
An diesem Punkt kann ich diese Schaltfläche ziehen und in eine andere vom gleichen Typ ablegen, für die die Eigenschaft "acceptDrops" im Qt-Designer auf "true" gesetzt ist.Ich möchte jedoch das Ziehen einiger Schaltflächen einschränken (möglicherweise durch Einstellen der Hauptdatei mit der UpdateUi-Methode), da einige nur zum Akzeptieren von Ablagen dienen.
UPDATE 2: Jetzt versuche ich, eine Klasse zu schreiben, die Linien oder "Drähte" malt, die diese Knöpfe verbinden.
Ich versuche, eine Linie zwischen zwei Widgets (zwei Drucktasten) in einer Grafikansicht mit ihren Positionen als Referenz zu zeichnen. Aber wenn ich es versuche, wird die Linie an einer falschen Stelle gezogen. Ich habe auch versucht, Funktionen wie mapToGlobal oder mapToParent mit unterschiedlichen Ergebnissen zu verwenden, aber immer noch falsch. In der gleichen Klasse habe ich eine andere Methode, die Linien mit der Maus zeichnet und ok funktioniert. Ich habe es als Referenz oder Beispiel genommen, aber es scheint, dass die Ereignisposition ein anderes Koordinatensystem hat. Nun, ich weiß nicht, warum das passiert.
Die Schaltflächen und die Grafikansicht befinden sich in einem Widget, das sich auch in einem Fenster befindet.
Hier ist es die Klasse, die Methode, über die wir sprechen, stammt von PyQt4-Import QtGui, QtCore
class WiringGraphicsView(QtGui.QGraphicsView):
def __init__(self, parent):
QtGui.QGraphicsView.__init__(self, parent)
self.setScene(QtGui.QGraphicsScene(self))
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
def mousePressEvent(self, event):
self._start = event.pos()
def mouseReleaseEvent(self, event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0) )
pen = QtGui.QPen(brush, 2)
line = QtGui.QGraphicsLineItem(QtCore.QLineF(start, end))
line.setPen(pen)
self.scene().addItem( line )
def paintWire(self, start_widget, end_widget):
start_position = QtCore.QPointF(self.mapToScene(start_widget.pos()))
end_position = QtCore.QPointF(self.mapToScene(end_widget.pos()))
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0) )
pen = QtGui.QPen(brush, 2)
line = QtGui.QGraphicsLineItem(QtCore.QLineF(start_position, end_position))
line.setPen(pen)
self.scene().addItem( line )
Wenn es einen besseren Weg gibt, dies umzusetzen, sagen Sie es mir bitte.