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()并对此作出反应,但是对于许多不同的窗口小部件,这也是很多工作.
有更优雅的解决方案吗?
好吧,您可以扩展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)
我相信您得到的两个答案都是错误的。它们适用于简单的情况,但非常脆弱且笨拙。我认为最好的解决方案是您在问题中实际提出的建议。我会去连接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)
优势显而易见。该代码简短明了。您仅连接一个信号插槽,就无需捕获和处理事件。创建对象后,它对布局所做的任何更改都能很好地响应。而且,如果您想优化不必要的重绘,则应该缓存是否有任何子对象都已集中信息,并且仅在更改此缓存值时才更改样式表。那么解决方案将是完美的。