Child-Widget anzeigen oder verbergen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Vortex
User
Beiträge: 16
Registriert: Sonntag 13. August 2006, 14:12
Kontaktdaten:

Hallo zusammen.

Ich habe zwei Widgets, die folgendermaßen angeordnet sind:

Code: Alles auswählen

-----------------------------------------------
|                A                             |
|                                              |
|                                              |
|          ------------------------------      |
|          |                            |      |
|          |         B                  |      |
|          |                            |      |
|          |                            |      |
|          ------------------------------      |
|                                              |
-----------------------------------------------

A und B sind QWidgets. A ist das parent von B (B befindet sich "in" A).

B ist normalerweise unsichtbar. setVisible(False)

Wenn der Mauszeiger A betritt (enterEvent), wird B angezeigt.
Wenn der Mauszeiger A verlässt (leaveEvent), wird B wieder versteckt.

Das Problem:

Wenn der Mauszeiger B betritt, erhält A ein leaveEvent und B wird versteckt. Dadurch erhält A wieder ein enterEvent und B wird wieder angezeigt. Bewegt man den Mauszeiger also über B hinweg, fängt B an zu flackern, da es ständig aus- und eingeblendet wird.

Eigentlich soll B nur versteckt werden, wenn der Mauszeiger die gesamte Fläche von A und B verlässt.
Wenn der Mauszeiger über B steht, soll es trotzdem angezeigt bleiben. Nur wenn der Mauszeiger die Fläche komplett verlässt, man also die Maus "nach außen" von A wegbewegt oder z.B. ein anderes Fenster in den Vordergrund holt, soll B versteckt werden.

Wie kann ich das bewerkstelligen?
franzf
User
Beiträge: 78
Registriert: Samstag 29. August 2009, 10:21

Du kannst A als Eventfilter von B installieren, und dort (in A::eventFilter) das QEvent::Enter + QEvent::Leave abfangen und entsprechend ne Member "bool m_BHovered" setzen. in A::leaveEvent() darfst du das B.hide() nur machen falls m_BHovered == False.
Soweit zur Theorie :)

Ciao
Franz
franzf
User
Beiträge: 78
Registriert: Samstag 29. August 2009, 10:21

OK, die Theorie ist nicht mit der Praxis vereinbar, denn leider wird eventFilter() nach dem leaveEvent() abgearbeitet, wodurch das Flackern bleibt.
Aber eine andere Lösung funktioniert eh besser, nämlich in leaveEvent() fragen ob QCursor::pos() evtl. noch im Widget liegt :)

Das prinzipielle Problem besteht aber eh nur, weil dein childWidget gar keinen parent hat :P Dadurch hast du das Problem, dass du dein aufpoppendes Widget immer mitziehen musst, falls dein Widget bewegt wird.

Ich hab mal ein halbwegs funktionierendes Beispiel um das prinzipielle Vorgehen zu verdeutlichen. Der eventFilter war nötig, falls du nämlich von dem popup direkt aus beiden Widgets rausfährst, hatte dein Widget ja bereits ein leaveEvent, und das popup bleibt sichtbar, was ja auch nicht erwünscht ist.

Code: Alles auswählen

import PyQt4.QtGui as q4g
import PyQt4.QtCore as q4c
import PyQt4.Qt as qt
import sys

class Widget(q4g.QWidget):
    def __init__(self, parent=None):
        q4g.QWidget.__init__(self, parent)
        self.hoverLabel = q4g.QLabel("Hover...")
        self.hoverLabel.setWindowFlags(self.hoverLabel.windowFlags() | qt.Qt.FramelessWindowHint)
        self.hoverLabel.hide()
        self.move(100,100)
        rect = q4c.QRect(0, 0, 100, 100)
        rect.moveTopLeft(self.mapToGlobal(q4c.QPoint(50, 50)))
        self.hoverLabel.setGeometry(rect)
        self.hoverLabel.setLineWidth(2)
        self.hoverLabel.setFrameShape(q4g.QFrame.Box)
        self.hoverLabel.installEventFilter(self)

    def eventFilter(self, obj, evt):
        if obj == self.hoverLabel:
            if evt.type() == q4c.QEvent.Leave:
                if not self.rect().contains(self.mapFromGlobal(q4g.QCursor.pos())):
                    self.hoverLabel.hide()
        return False

    def enterEvent(self, event):
        if not self.hoverLabel.isVisible():
            self.hoverLabel.show()

    def leaveEvent(self, event):
        if not self.rect().contains(self.mapFromGlobal(q4g.QCursor.pos())):
            self.hoverLabel.hide()

if __name__ == "__main__":
    app = q4g.QApplication(sys.argv)
    win = Widget()
    win.show()
    app.exec_()
Wie gesagt solltest du aber noch moveEvent() implementieren, um da auch das self.hoverLabel mitzuziehen, nicht dass das irgendwann komplett wo anders aufpoppt :P

Grüße
Franz
Antworten