恢复QMainWindow的浮动工具栏时出现问题 [英] Problem in restoring floating toolbar for QMainWindow

查看:129
本文介绍了恢复QMainWindow的浮动工具栏时出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

还原浮动工具栏中具有QCombobox的QMainWindow状态时,我看到一个问题.恢复浮动工具栏后,我的QCombobox无法获得焦点,直到我单击工具栏手柄并将其移动.以下是显示问题的gif,使用QT 5.13.

I am seeing a problem while restoring QMainWindow state having QCombobox in floating toolbar. After restoring floating toolbar, my QCombobox is not able to get focus until i click on toolbar handle and move it. Following is gif showing problem, Using QT 5.13.

floating_toolbar.pro文件

File floating_toolbar.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = floating_toolbar
TEMPLATE = app


DEFINES += QT_DEPRECATED_WARNINGS

 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

CONFIG += c++11

SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

文件:main.cpp

File : main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

文件:mainwindow.h

File : mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    void closeEvent(QCloseEvent *event);
    void readSettings();
    bool eventFilter(QObject* xObj, QEvent* xEvent);
    ~MainWindow();

    public slots:
    void mCheck();
};

#endif // MAINWINDOW_H

文件:mainwindow.cpp

File : mainwindow.cpp

#include "mainwindow.h"
#include <QToolBar>
#include <QComboBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLayout>
#include <QSettings>
#include <QEvent>
#include <QDebug>
#include <QMouseEvent>
#include <QApplication>



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QToolBar* lToolbar = new QToolBar(this);
    QComboBox* lComobox = new QComboBox(this);
    lComobox->setEditable(true);

    lToolbar->setWindowTitle("MyToolBar");
    lToolbar->setObjectName("NiceBaby");
    lToolbar->addWidget(lComobox);
    //lToolbar->addAction("check", lComobox, SLOT(clearEditText()));


    addToolBar(lToolbar);
    lToolbar->installEventFilter(this);
    readSettings();


}

void MainWindow::mCheck()
{

}
void MainWindow::closeEvent(QCloseEvent *event)
{
    QSettings settings("MyCompany", "MyApp");
    settings.setValue("windowState", saveState());
    QMainWindow::closeEvent(event);
}
void MainWindow::readSettings()
{
    QSettings settings("MyCompany", "MyApp");
    restoreState(settings.value("windowState").toByteArray());
}

MainWindow::~MainWindow()
{

}

bool MainWindow::eventFilter(QObject* xObj, QEvent* xEvent)
{
    //qDebug()<<xEvent->type();

    return QMainWindow::eventFilter(xObj, xEvent);
}

推荐答案

好,一种解决方法是在工具栏首次显示并浮动时重置工具栏上的窗口标志.通过查看工具栏

OK, a workaround is to reset the window flags on the toolbar when it is first shown and is floating. I tracked this down by seeing what happens once a toolbar is dropped after being dragged (but not plugged into main window). (It calls setWindowState() and all that does in this situation is hide the toolbar, call updateWindowFlags(), and show it again).

这可以从 QMainWindow :: showEvent()或从安装在 QToolBar 上的 eventFilter 处理.我认为这比前者更简单.

This could be handled from the QMainWindow::showEvent() or from the eventFilter installed onto the QToolBar. I think it's simpler from the former.

UPDATE :实际上,每当第一次显示工具栏时都会发生此问题,即使不是在应用启动时也是如此.应用启动后,由用户从切换视图菜单中选择.我也更新了下面的代码以解决该问题.并查看下面有关最小化主窗口的另一个问题的注释.

UPDATE: This problem actually happens whenever the toolbar is first shown even if not at app startup, e.g. from the toggle view menu by the user once app starts. I updated the code below to fix that issue as well. And see notes below about another issue with minimizing the main window.

我将其从MCVE添加到 MainWindow 类中:

I added this to the MainWindow class from the MCVE:

  protected:
    void showEvent(QShowEvent *e) override {
      QMainWindow::showEvent(e);
#ifdef Q_OS_LINUX
      if (lToolbar->isFloating() 
          // remove the next condition and the toolsbar will get hidden the 2nd time main window is minimized.
          && lToolbar->windowFlags().testFlag(Qt::X11BypassWindowManagerHint)  
          ) {
        const bool vis = !lToolbar->isHidden();
        qDebug() << lToolbar->isFloating() << vis << lToolbar->windowFlags();
        lToolbar->hide();
        lToolbar->setWindowFlag(Qt::X11BypassWindowManagerHint, false);
        if (vis)
          lToolbar->show();
#endif
    }

    QToolBar* lToolbar;  // Use this in MainWindow constructor to save the instance pointer.

我还注意到最初浮动的工具栏上的另一个问题.当主窗口最小化时,工具栏不会隐藏,而是停留在屏幕上.无论工具栏中的内容是什么(例如,没有组合框,只有QActions).该解决方法也可以解决该问题(请参阅代码注释),但仅第二次将窗口最小化.首先需要一个更好的解决方法.

I also noticed another issue with the initially-floating toolbar. When the main window is minimized, the toolbar doesn't get hidden but stays where it was on the screen. Regardless of what is in the toolbar (eg. no combo box, just QActions). This workaround could also sort-of address that issue (see code comment), but only the 2nd time the window is minimized. Needs a better workaround for the first minimize.

其他人可以确认吗?这个问题可能比可编辑的组合要大,如果以前没有人注意到我,我会感到惊讶.

Can others confirm this? Potentially a larger issue than the editable combo and I'd be surprised if no one noticed before.

我想这应该以Qt错误的形式提交.

I guess this should be filed as a Qt bug either way.

UPDATE2 :此版本还解决了最小化问题.我猜想在 QMainWindow :: showEvent()之后会发生一些改变工具栏行为的行为.这就解释了为什么上述解决方法仅在第一次最小化后有效.因此,安排工具栏修复程序"以供日后使用也可以解决此问题.

UPDATE2: This version also fixes the minimize issue. I guess something happens after the QMainWindow::showEvent() that changes how the toolbar behaves. Which explains why the above workaround works only after the 1st minimize. So scheduling the toolbar "fix" for later works around that also.

class MainWindow : public QMainWindow
{
...
#ifdef Q_OS_LINUX
  protected:
    void showEvent(QShowEvent *e) override
    {
      QMainWindow::showEvent(e);
      if (lToolbar->isFloating() && lToolbar->windowFlags().testFlag(Qt::X11BypassWindowManagerHint) ) {
        //  QMainWindow::show() after QMainWindow::restoreState() will break the minimizing again so we should delay calling adjustToolbar().
        QMetaObject::invokeMethod(this, "adjustToolbar", Qt::QueuedConnection);
        // If we're sure restoreState() is only called after show() then adjustToolbar() could be called here directly instead.
        //adjustToolbar();
      }
    }

  private slots:
    void adjustToolbar() const
    {
      const bool vis = !lToolbar->isHidden();
      qDebug() << lToolbar->isFloating() << vis << lToolbar->windowFlags();
      lToolbar->hide();
      lToolbar->setWindowFlag(Qt::X11BypassWindowManagerHint, false);
      if (vis)
        lToolbar->show();
    }
#endif

  private:
    QToolBar* lToolbar;
};

添加:QcodeBar子类,它自己应用替代方法,而在QMainWindow 中不需要任何特殊操作.最小修复仍然仅在 adjustToolbar()函数排队时有效,如果 restoreState()仅在 show()之后调用,则最小修复(请参阅代码注释).

ADDED: A QToolBar subclass which applies the workaround on its own, nothing special needed in the QMainWindow. The minimize fix still only works when the adjustToolbar() function is queued or if restoreState() is only called after show() (see code comments).

class ToolBar : public QToolBar
{
    Q_OBJECT
  public:
    using QToolBar::QToolBar;

#ifdef Q_OS_LINUX
  protected:
    void showEvent(QShowEvent *e) override
    {
      QToolBar::showEvent(e);
      if (isFloating() && windowFlags().testFlag(Qt::X11BypassWindowManagerHint) ) {
        //  QMainWindow::show() after QMainWindow::restoreState() will break the minimizing again so we should delay calling adjustToolbar().
        QMetaObject::invokeMethod(this, "adjustToolbar", Qt::QueuedConnection);
        // If we're sure restoreState() is only called after show() then adjustToolbar() could be called here directly instead.
        //adjustToolbar();
      }
    }

  private slots:
    void adjustToolbar()
    {
      const bool vis = !isHidden();
      hide();
      setWindowFlag(Qt::X11BypassWindowManagerHint, false);
      if (vis)
        show();
    }
#endif
};

UPDATE3 :最小化问题还存在于浮动 QDockWidget 如果 QMainWindow 状态在恢复之前如图所示.实际上,对于较旧"的Qt版本,浮动窗口小部件根本不会显示(对于< = 5.9.5则不显示,但对于> = 5.12.4则不显示,尝试ATM之间没有任何区别).因此正确的方法是先在主窗口中先 show(),然后先然后 restoreState().不幸的是,这似乎不适用于 QToolBar .

UPDATE3: The minimizing issue also exists with floating QDockWidget if the QMainWindow state is restored before it is shown. In fact with "older" Qt versions the floating widget doesn't show up at all (doesn't with <= 5.9.5 but does with >= 5.12.4, don't have anything in between to try ATM). So the proper approach is to show() the main window first and then restoreState(). Unfortunately this doesn't seem to work for QToolBar.

UPDATE4 :归档为 QTBUG-78293

这篇关于恢复QMainWindow的浮动工具栏时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆