如何在子窗口小部件具有焦点时更改父窗口小部件的背景?

Elw*_*ood 8 qt focus qt4 qwidget

我想强调一个QFrame,如果它的一个子小部件有焦点(所以用户知道在哪里寻找光标;-)

用的东西

ui->frame->setFocusPolicy(Qt::StrongFocus);
ui->frame->setStyleSheet("QFrame:focus {background-color: #FFFFCC;}");
Run Code Online (Sandbox Code Playgroud)

当我点击它时突出显示QFrame,但是一旦选择了其中一个子窗口小部件,它就会失去焦点.

可能的方法:

  • connect() QApplication::focusChanged(old,now)如果它是我的QFrame的孩子,我可以检查每个新对象,但这会变得混乱.

  • 我也可以子类化每个子窗口小部件并重新实现focusInEvent()/ focusOutEvent()并对此作出反应,但是对于许多不同的窗口小部件,这也是很多工作.

有更优雅的解决方案吗?

Arc*_*hie 8

好吧,您可以扩展QFrame以使其监听其子窗口小部件的焦点更改.或者您也可以在要捕获的子窗口小部件上安装事件过滤器QFocusEvent.

这是一个例子:

MyFrame.h

#ifndef MYFRAME_H
#define MYFRAME_H

#include <QFrame>

class MyFrame : public QFrame
{
    Q_OBJECT

public:

    explicit MyFrame(QWidget* parent = 0, Qt::WindowFlags f = 0);

    void hookChildrenWidgetsFocus();

protected:

    bool eventFilter(QObject *object, QEvent *event);

private:

    QString m_originalStyleSheet;
};

#endif // MYFRAME_H
Run Code Online (Sandbox Code Playgroud)

MyFrame.cpp

#include <QEvent>
#include "MyFrame.h"

MyFrame::MyFrame(QWidget *parent, Qt::WindowFlags f)
    : QFrame(parent, f)
{
    m_originalStyleSheet = styleSheet();
}

void MyFrame::hookChildrenWidgetsFocus()
{
    foreach (QObject *child, children()) {
        if (child->isWidgetType()) {
            child->installEventFilter(this);
        }
    }
}

bool MyFrame::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::FocusIn) {
        setStyleSheet("background-color: #FFFFCC;");
    } else if (event->type() == QEvent::FocusOut) {
        setStyleSheet(m_originalStyleSheet);
    }

    return QObject::eventFilter(object, event);
}
Run Code Online (Sandbox Code Playgroud)

MainWindow.cpp

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLineEdit>
#include "MyFrame.h"
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setWindowTitle(tr("Test"));

    MyFrame *frame1 = new MyFrame(this);
    frame1->setLayout(new QVBoxLayout());
    frame1->layout()->addWidget(new QLineEdit());
    frame1->layout()->addWidget(new QLineEdit());
    frame1->layout()->addWidget(new QLineEdit());
    frame1->hookChildrenWidgetsFocus();

    MyFrame *frame2 = new MyFrame(this);
    frame2->setLayout(new QVBoxLayout());
    frame2->layout()->addWidget(new QLineEdit());
    frame2->layout()->addWidget(new QLineEdit());
    frame2->layout()->addWidget(new QLineEdit());
    frame2->hookChildrenWidgetsFocus();

    QHBoxLayout *centralLayout = new QHBoxLayout();
    centralLayout->addWidget(frame1);
    centralLayout->addWidget(frame2);

    QWidget *centralWidget = new QWidget();
    centralWidget->setLayout(centralLayout);

    setCentralWidget(centralWidget);
}
Run Code Online (Sandbox Code Playgroud)


V.K*_*.K. 5

我相信您得到的两个答案都是错误的。它们适用于简单的情况,但非常脆弱且笨拙。我认为最好的解决方案是您在问题中实际提出的建议。我会去连接QApplication::focusChanged(from, to)。您只需将主框架对象连接到此信号,然后在插槽中检查该to对象(获得焦点的对象)是否为框架对象的子代。

Frame::Frame(...)
{
// ...
  connect(qApp, &QApplication::focusChanged, this, &Frame::onFocusChanged);
// ...
}

// a private method of your Frame object
void Frame::onFocusChanged(QWidget *from, QWidget *to)
{
  auto w = to;
  while (w != nullptr && w != this)
    w = w->parentWidget();

  if (w == this) // a child (or self) is focused
    setStylesheet(highlightedStylesheet);
  else // something else is focused
    setStylesheet(normalStylesheet);
}
Run Code Online (Sandbox Code Playgroud)

优势显而易见。该代码简短明了。您仅连接一个信号插槽,就无需捕获和处理事件。创建对象后,它对布局所做的任何更改都能很好地响应。而且,如果您想优化不必要的重绘,则应该缓存是否有任何子对象都已集中信息,并且仅在更改此缓存值时才更改样式表。那么解决方案将是完美的。