Qt: Mehrere Mainwindows ohne Fokusverlust



  • Hi,

    hauptsächlich um Multiscreen-Anwendungen zu unterstützen, möchte ich gerne zwei QMainWindows anbieten.

    Das klappt prinzipiell auch, es gibt jedoch einige Nachteile unter Windows, während ich andere Betriebssysteme nicht getestet habe.

    Was mich hauptsächlich stört, ist, dass ich bei fokussierten Window1 einen Extraklick auf Window2 benötige, um dort z.B. einen Button zu klicken, ein Textfeld zu fokussieren usw. Ich muss also einmal klicken, dann gibt es dort den Fokus, und ein zweites mal, um die eigentliche Aktion auszuführen. Manchmal geht es auch mit einem Klick, dauert aber beträchtlich länger, weil anscheinend irgendein Kontext geladen wird.

    Der Sinn bei mir soll jedoch sein, dass das zweite QMainWindow wie eine Erweiterung des ersten dient, ich möchte ganz einfach die volle Fläche von zwei Bildschirmen mit meinem Programm nutzbar machen. Ich bräuchte quasi gar nicht zwei QMainWindows, wenn ich einfach eines haben könnte, welches sich über mehrere Desktops komplett erstreckt, was ja aber nicht funktioniert.

    Hat jemand einen Lösungsvorschlag?

    Viele Grüße
    Eisflamme



  • Du kannst vielleicht einen nicht modalen Dialog mit deinem MainWindows als Owner anzeigen. Ich weiß nicht, ob das mit Qt Mitteln ohne weiteres geht und welche WindowFlags man dafür setzen müsste, musst evtl. rumprobieren. Ansonsten müsste das über WinApi gehen.



  • Huhu,

    und warum nicht QMainWindow + QDockWidgets?

    Und mit Hilfe von QMainWindow::saveState und QMainWindow::restoreState lassen sich auch die Widget Positionen ganz einfach speichern.

    Gruß

    EDIT

    class MyAutoFocus : public QObject {
    public:
      virtual bool eventFilter(QObject* obj, QEvent* event) {
        if (event->type() == QEvent::Enter) {
          QWidget* w = qobject_cast<QMainWindow*>(obj);
          if (!w) {
            w = qobject_cast<QDockWidget*>(obj);
          }
    
          if (w) {
            // funktioniert bei mir leider nicht, allerdings wäre das hier die richtige Stelle ... um das QWidget dem Focus zu geben ...
            w->setFocus();
          }
        }
    
        return QObject::eventFilter(obj, event);
      }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        MyAutoFocus myAutoFocus;
    
        MyMainWindow w;
        w.installEventFilter(&myAutoFocus);
    
        QDockWidget* dockWidget = new QDockWidget("Test", &w);
        dockWidget->installEventFilter(&myAutoFocus);
        w.addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, dockWidget);      
    
        w.show();
        return a.exec();
    }
    


  • Mechanics:
    Klingt interessant, werd ich mal probieren.

    __jb__:
    Docks will ich ja auch nutzen, aber ich will auf Bildschirm1 und 2 gleichermaßen Docking-Stationen haben. Split-Screen auf Bildschirm2 für zwei Docks wäre z.B., was ich möchte.

    Was wäre sonst dein Vorschlag? Beim Abdocken einfach manuell irgendwo auf Bildschirm2 hinschieben und als freies Fenster belassen?

    saveState funktioniert bei mir übrigens nicht. Er merkt sich zwar ein paar Docking-Details, aber nicht alles...



  • Also mit folgendem Code funktioniert auf jeden Fall die Autoaktivierung der einzelnen QMainWindows & QDockWidgets.

    class MyAutoActiveWindow : public QObject {
    public:
      virtual bool eventFilter(QObject* obj, QEvent* event) {
        if (event->type() == QEvent::Enter) {
          QWidget* w = qobject_cast<QMainWindow*>(obj);
          if (!w) {
            QDockWidget* dw = qobject_cast<QDockWidget*>(obj);
            if (dw->isFloating()) {
              w = dw;
            }
          }
    
          if (w && !w->isActiveWindow()) {
            w->activateWindow();
          }
        }
    
        return QObject::eventFilter(obj, event);
      }
    };
    
    int main(int argc, char *argv[]) {
      QApplication a(argc, argv);
    
      MyAutoActiveWindow myAutoActiveWindow;
    
      int i = 0;
      std::vector<QMainWindow> mainWindows(4);
      for (QMainWindow& w : mainWindows) {
        w.installEventFilter(&myAutoActiveWindow);
        QDockWidget* dockWidget = new QDockWidget(QString("Dock: %1").arg(QString::number(++i)));
        dockWidget->installEventFilter(&myAutoActiveWindow);
        w.addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, dockWidget);
        w.show();
      }
    
      return a.exec();
    }
    

    Die DockWidgets lassen sich nur beim initialen hinzugefügten QMainWidget wieder andocken. 😕 Vermutlich müsste man hier ein Handling einbauen, dass sich der Parent dynamisch ändern kann ... Außer diese Limitierung ist dir egal. Eine bessere Lösung fällt mir dazu nicht ein.

    Eisflamme schrieb:

    saveState funktioniert bei mir übrigens nicht. Er merkt sich zwar ein paar Docking-Details, aber nicht alles...

    Stimmt an der Stelle die Parent-Beziehungen? Und hast Du bei jeder Qt Klasse auch brav das Q_OBJECT Makro eingefügt? Das wäre jetzt so meine Ideen warum es nicht richtig tut.



  • Das Snippet für Auto-Fokus gefällt mir ganz gut 🙂 Wenn das performant genug läuft (Fokus dauert ja manchmal), könnte ich damit vielleicht gut zwei QMainWindows basteln. 🙂 Danke auf alle Fälle schon mal dafür!

    Und ja, den Parent bei Docks switchen kriegt man vermutlich irgendwie hin. Habe mal einen Codeschnipsel dazu gesehen, der irgendwas ähnliches gemacht hat, glaube ich. Das bräuchte ich jedoch auch dringend, das zweite Fenster soll ja schließlich optional sein, sonst hat ein Benutzer ohne zweiten Bildschirm plötzlich nicht alle Features zur Verfügung.

    Zu saveState:

    Q_OBJECT nutze ich in jedem meiner dockbaren Widgets, aber prüfe ich vielleicht nochmal.

    Er hat sich irgendeine Eigenschaft gemerkt, z.B. ob er beim linken oder rechten Dock angedockt war... aber nicht ob getabt oder bei mehreren Docks die Reihenfolge davon oder z.B. bei West das Verhältnis der beiden Heights... all diese Infos brauche ich natürlich und da glaube ich, dass saveState sich so was einfach nicht merkt, weil es den QT-Entwicklern mal wieder zu egal war...



  • Eisflamme schrieb:

    Er hat sich irgendeine Eigenschaft gemerkt, z.B. ob er beim linken oder rechten Dock angedockt war... aber nicht ob getabt oder bei mehreren Docks die Reihenfolge davon oder z.B. bei West das Verhältnis der beiden Heights... all diese Infos brauche ich natürlich und da glaube ich, dass saveState sich so was einfach nicht merkt, weil es den QT-Entwicklern mal wieder zu egal war...

    Dem wiederspreche ich. In der Firma wo ich arbeite verwenden wir auch Qt(5) mit MainWindow und DockWidgets für einen Editor. Und dort wird sauber der Zustand (ob und an welcher stelle das DockWidget gedockt ist, ob getapped oder nicht) jedes offenen Docks gespeichert und restored.

    Wobei man beachten muss, dass der objectname jedes DockWidgets eindeutig sein muss, da die Einstellungen anhand dieses namens referenziert werden.



  • Objectname nutze ich gar nicht! Vielleicht liegt's daran, das probiere ich, danke 🙂



  • Lag tatsächlich daran!! 😋

    Auch das activate-Skript habe ich getestet. Wenn sich Fenster überlappen, rückt das andere natürlich automatisch in den Hintergrund. Das finde ich aber sogar ziemlich angenehm. 🙂

    Umdocken habe ich noch nicht ausprobiert. Wenn ich rausfinden sollte, wie das geht, poste ich's hier.



  • Eisflamme schrieb:

    Lag tatsächlich daran!! 😋

    Top, auch wieder was dazu gelernt.

    Eisflamme schrieb:

    Auch das activate-Skript habe ich getestet. Wenn sich Fenster überlappen, rückt das andere natürlich automatisch in den Hintergrund. Das finde ich aber sogar ziemlich angenehm. 🙂

    Super, freut mich!
    Edit: Ich hab gestern gelernt, das Fokus & aktives Fenster zweierlei sind (s. StrongFocus). Daher würde sich evtl. noch anbieten ein "setFocus()" einzubauen.

    Eisflamme schrieb:

    Umdocken habe ich noch nicht ausprobiert. Wenn ich rausfinden sollte, wie das geht, poste ich's hier.

    Ja, das wäre klasse, würde mich interessieren wie das geht. Mein erster Versuch ist in einem ApplicationCrash geendet.



  • Eisflamme schrieb:

    Umdocken habe ich noch nicht ausprobiert. Wenn ich rausfinden sollte, wie das geht, poste ich's hier.

    Fürs Umdocken müsstest du AFAIK den parent des Dockwidgets ändern auf das main window in dem es sich andocken lassen soll


Log in to reply