Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Qt 如何更改父窗口小部件';子窗口小部件具有焦点时的背景?_Qt_Qt4_Focus_Qwidget - Fatal编程技术网

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

Qt 如何更改父窗口小部件';子窗口小部件具有焦点时的背景?,qt,qt4,focus,qwidget,Qt,Qt4,Focus,Qwidget,如果QFrame的一个子部件具有焦点,我想突出显示QFrame(这样用户就知道在哪里查找光标;-) 用一些东西 ui->frame->setFocusPolicy(Qt::StrongFocus); ui->frame->setStyleSheet("QFrame:focus {background-color: #FFFFCC;}"); 当我点击QFrame时,它会高亮显示,但一旦它的一个子部件被选中,它就会失去焦点 可能的办法: 我可以connect()QApp

如果QFrame的一个子部件具有焦点,我想突出显示QFrame(这样用户就知道在哪里查找光标;-)

用一些东西

ui->frame->setFocusPolicy(Qt::StrongFocus);
ui->frame->setStyleSheet("QFrame:focus {background-color: #FFFFCC;}");
当我点击QFrame时,它会高亮显示,但一旦它的一个子部件被选中,它就会失去焦点

可能的办法:

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

  • 我还可以对每个子窗口小部件进行子类化,并重新实现
    focusInEvent()
    /
    focusOutEvent()
    ,并对其做出反应,但对于许多不同的窗口小部件,这也是一项艰巨的工作


有更优雅的解决方案吗?

好吧,您可以扩展
QFrame
,让它监听子部件的焦点变化。 或者,您也可以在子窗口小部件上安装事件过滤器,以捕获
QFocusEvent

以下是一个例子:

MyFrame.h

#如果取消我的框架#
#定义我的框架
#包括
类MyFrame:publicqframe
{
Q_对象
公众:
显式MyFrame(QWidget*parent=0,Qt::WindowFlags f=0);
void hookChildrenWidgetsFocus();
受保护的:
bool事件过滤器(QObject*对象,QEvent*事件);
私人:
QString m_原始样式表;
};
#endif//MYFRAME\u H
MyFrame.cpp

#包括
#包括“MyFrame.h”
MyFrame::MyFrame(QWidget*父项,Qt::WindowFlags f)
:QFrame(父对象,f)
{
m_originalStyleSheet=样式表();
}
void MyFrame::hookChildrenWidgetsFocus()
{
foreach(QObject*child,children()){
如果(子->isWidgetType()){
子->installEventFilter(此);
}
}
}
bool MyFrame::eventFilter(QObject*对象,QEvent*事件)
{
如果(事件->类型()==QEvent::FocusIn){
设置样式表(“背景色:#FFFFCC;”);
}else if(事件->类型()==QEvent::FocusOut){
设置样式表(m_原始样式表);
}
返回QObject::eventFilter(对象,事件);
}
MainWindow.cpp

#包括
#包括
#包括
#包括“MyFrame.h”
#包括“mainwindow.h”
主窗口::主窗口(QWidget*父窗口):
QMainWindow(父窗口)
{
设置窗口标题(tr(“测试”);
MyFrame*frame1=新的MyFrame(此);
frame1->setLayout(新的QVBoxLayout());
frame1->layout()->addWidget(新的QLineEdit());
frame1->layout()->addWidget(新的QLineEdit());
frame1->layout()->addWidget(新的QLineEdit());
frame1->hookChildrenWidgetsFocus();
MyFrame*frame2=新的MyFrame(此);
frame2->setLayout(新的QVBoxLayout());
frame2->layout()->addWidget(新的QLineEdit());
frame2->layout()->addWidget(新的QLineEdit());
frame2->layout()->addWidget(新的QLineEdit());
frame2->hookChildrenWidgetsFocus();
QHBoxLayout*centralLayout=新的QHBoxLayout();
centralLayout->addWidget(框架1);
centralLayout->addWidget(框架2);
QWidget*centralWidget=新的QWidget();
centralWidget->setLayout(centralLayout);
setCentralWidget(centralWidget);
}

首先,创建
QFrame
的一个简单子类,它重新实现
eventFilter(QObject*,QEvent*)
虚拟函数:

class MyFrame : public QFrame {
    Q_OBJECT

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

    virtual bool eventFilter(QObject *watched, QEvent *event);
};
使用
MyFrame
而不是
QFrame
来包含小部件。然后,在代码中创建
MyFrame
中包含的小部件的某个地方,在这些小部件上安装一个事件过滤器:

    // ...
    m_myFrame = new MyFrame(parentWidget);
    QVBoxLayout *layout = new QVBoxLayout(myFrame);
    m_button = new QPushButton("Widget 1", myFrame);

    layout->addWidget(m_button);
    m_button->installEventFilter(myFrame);
    //...
此时,
MyFrame::eventFilter()
将在将任何事件传递到小部件之前调用,让您在小部件意识到之前对其进行操作。在
MyFrame::eventFilter()
中,如果要筛选出事件(即不希望小部件处理事件),则返回
true
,否则返回
false

bool MyFrame::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == m_button) { // An event occured on m_button
        switch (event -> type()) {
            case QEvent::FocusIn:
                // Change the stylesheet of the frame
                break;
            case QEvent::FocusOut:
                // Change the stylesheet back
                break;
            default:
                break;
        }
    }

    return false; // We always want the event to propagate, so always return false
}

我相信你得到的两个答案都是错误的。它们适用于简单的箱子,但极其脆弱和笨拙。我相信最好的解决办法就是你在问题中实际提出的建议。我会选择连接到
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);
}

优势是显而易见的。这段代码简短明了。您只连接一个信号插槽,不需要捕获和处理事件。它可以很好地响应创建对象后所做的任何布局更改。如果你想优化掉不必要的重画,你应该缓存信息,不管是否有子对象被聚焦,并且只在这个缓存的值被改变时才改变样式表。那么解决方案将是完美的。

阿尔奇,谢谢你的回复。你能给我一个关于如何扩展QFrame的指针吗?太好了。我特别喜欢hookchildrenwidgetsfous()的想法。(但我有点良心不好,因为我剥夺了弗雷德的认可,他早些时候提出了类似的方法。非常感谢你们两位!)恐怕这不是公认的答案。它适用于这种简单的情况,但远不是一个好的解决方案。它非常脆弱,很容易出错。1) 如果布局变得动态,并且在运行时添加或删除了一些子窗口小部件,该怎么办。2) 如果该对象希望在其他对象及其焦点事件(子对象除外)上安装事件过滤器,则可能会执行其他操作。@V.K.我认为您试图将特定的实现问题引入其中。拟议的解决方案并不意味着具有普遍性。作为一名开发人员,您知道特定设计的局限性(例如,您是否希望使用其他事件过滤器或动态布局),因此您应该根据自己的设计调整此代码段。无论如何,这些都不是原问题中提到的先决条件。@Archie我认为一个人的目标应该是最简单和最简单的
    // ...
    m_myFrame = new MyFrame(parentWidget);
    QVBoxLayout *layout = new QVBoxLayout(myFrame);
    m_button = new QPushButton("Widget 1", myFrame);

    layout->addWidget(m_button);
    m_button->installEventFilter(myFrame);
    //...
bool MyFrame::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == m_button) { // An event occured on m_button
        switch (event -> type()) {
            case QEvent::FocusIn:
                // Change the stylesheet of the frame
                break;
            case QEvent::FocusOut:
                // Change the stylesheet back
                break;
            default:
                break;
        }
    }

    return false; // We always want the event to propagate, so always return false
}
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);
}