QSplitter 在 QWidget 和 QTabWidget 之间变得难以区分

18

我想在一个水平的拆分器中将QWidget和QTabWidget并排放置。但是拆分器失去了它的形状,只有在将鼠标悬停在上面时才能知道它的位置。应该如何让它可见呢?

谢谢。

6个回答

30

由于QSplitterHandle(大多数人认为是“分隔符”)派生自QWidget,因此您可以将其他小部件添加到其中。以下是我过去解决此确切问题所做的内容:

// Now add the line to the splitter handle
// Note: index 0 handle is always hidden, index 1 is between the two widgets
QSplitterHandle *handle = pSplitter->handle(1);
QVBoxLayout *layout = new QVBoxLayout(handle);
layout->setSpacing(0);
layout->setMargin(0);

QFrame *line = new QFrame(handle);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);

这将在分隔符手柄上添加一个凹陷的线条。当然,您可以选择另一种样式的框架line,或者使用完全不同的小部件作为添加到分隔符手柄的小部件。


这太棒了。我只想添加一点,我更喜欢使用 QHBoxLayout,因为这样我可以为水平线分配 maximumWidth(对于水平分割器)。 - Phlucious
点赞是因为它确实有效,但这真的感觉像是一个笨拙的解决方案来应对Qt的bug... - Vincent Fourmond

12

我基于上面的代码,但它可以处理两种分隔器方向。 我只喜欢非不透明调整大小和非可折叠子级。 握把由三条平行线组成。您可以玩弄手柄宽度,但 7 的握力在 Windows 上看起来很好; 在 Linux 或 Mac 上还没有检查。

void helper::decorateSplitter(QSplitter* splitter, int index)
{
    Q_ASSERT(splitter != NULL);

    const int gripLength = 15; 
    const int gripWidth = 1;
    const int grips = 3;

    splitter->setOpaqueResize(false);
    splitter->setChildrenCollapsible(false);

    splitter->setHandleWidth(7);
    QSplitterHandle* handle = splitter->handle(index);
    Qt::Orientation orientation = splitter->orientation();
    QHBoxLayout* layout = new QHBoxLayout(handle);
    layout->setSpacing(0);
    layout->setMargin(0);

    if (orientation == Qt::Horizontal)
    {
        for (int i=0;i<grips;++i)
        {
            QFrame* line = new QFrame(handle);
            line->setMinimumSize(gripWidth, gripLength);
            line->setMaximumSize(gripWidth, gripLength);
            line->setFrameShape(QFrame::StyledPanel);
            layout->addWidget(line);
        }
    }
    else
    {
        //this will center the vertical grip
        //add a horizontal spacer
        layout->addStretch();
        //create the vertical grip
        QVBoxLayout* vbox = new QVBoxLayout;
        for (int i=0;i<grips;++i)
        {
            QFrame* line = new QFrame(handle);
            line->setMinimumSize(gripLength, gripWidth);
            line->setMaximumSize(gripLength, gripWidth);
            line->setFrameShape(QFrame::StyledPanel);
            vbox->addWidget(line);
        }
        layout->addLayout(vbox);
        //add another horizontal spacer
        layout->addStretch();
    }
}

1
这里可能是最好的解决方案,即使使用Qt5.6也是如此。谢谢! - Plouff
不得不将 gripWidth = 2 设置为可见的握把(Win7经典外观)。否则,这是一个很好的解决方案,本应该在Qt多年前就修复的问题。 - DerManu

9

这对于至少在WinXP和默认的Luna主题下的每个分隔符都是正确的(切换到经典模式可以解决问题)。 如果你想继续使用Luna,你可以改变分隔符的渲染方式,例如通过改变手柄的背景颜色。

int main(int argc, char *argv[])    {

    QApplication a(argc, argv);
    a.setStyleSheet("QSplitter::handle { background-color: gray }");
    MainWindow w;
    w.show();
    return a.exec();
}

您可以在https://doc.qt.io/qt-5/stylesheet-reference.html上找到更多关于Qt样式表的内容。


谢谢。这可以改变颜色,但我想改变分隔符的样式。这可能吗? - Narek
在Windows下,分割器的默认行为是绘制背景颜色。当被分割的组件默认也有背景颜色(QWidget)时,这是不好的。Windows的方式是给它们一个不同的颜色和/或凹陷的边框(QFrame支持边框)。如果您想使用relief,则必须更改样式(忘记样式表)。使用setStyle()来更改样式。例如,QPlastiqueStyle支持Reliefs。您可以将setStyle()应用于QApplication对象或仅应用于分割器(不建议)。我建议首先考虑提到的本地解决方案。 - merula
您可以重写 QSplitter::createHandle() 方法,以返回具有自定义绘制的分隔栏句柄。 - Kirill Gamazkov

1
你可以继承 QSplitter 并重写它的 protected virtual QSplitterHandle * QSplitter::createHandle() 方法,返回任何你想要的东西。
例如,你可以从这个重载方法中返回一个自定义绘图的 QSplitterHandle 子类。

0

使用 splitter_handles {} 函数并传入要添加手柄的 QSplitter:

#include "splitter_handles.h"
...
QSplitter spl {};
... // widgets added to 'spl'
plitter_handles {spl}; // adding handles
...

结果:

enter image description here

splitter_handles.h

#ifndef SPLITTER_HANDLES_H
#define SPLITTER_HANDLES_H

#include <QLayout>
#include <QPainter>
#include <QSplitter>

class handle : public QWidget
{
    Q_OBJECT

protected:
    void paintEvent(QPaintEvent *e) {
        Q_UNUSED(e);
        QPainter painter {this};
        painter.setPen(Qt::NoPen);
        painter.setBrush(Qt::Dense4Pattern);
        painter.drawRect(this->rect());
    }
};

class splitter_handles {
public:
    splitter_handles(QSplitter * spl) {
        const int width {7};
        spl->setHandleWidth(width);
        for(int h_idx {1}; h_idx < spl->count(); h_idx++) {
            auto l_handle {new handle {}};
            l_handle->setMaximumSize(width*2, width*2);

            auto layout {new QHBoxLayout {spl->handle(h_idx)}};
            layout->setSpacing(0);
            layout->setMargin(1);
            layout->addWidget(l_handle);
        }
    }
};

#endif // SPLITTER_HANDLES_H

main.c

#include <QApplication>
#include <QGroupBox>
#include <QLayout>
#include <QSplitter>

#include "splitter_handles.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    auto spl_v {new QSplitter {Qt::Vertical}};
    spl_v->addWidget(new QGroupBox {"box 1"});
    spl_v->addWidget(new QGroupBox {"box 2"});
    spl_v->addWidget(new QGroupBox {"box 3"});
    splitter_handles {spl_v}; // set handles

    auto wdg  {new QWidget {}};
    auto v_lt {new QVBoxLayout {wdg}};
    v_lt->addWidget(spl_v);
    v_lt->setMargin(0);

    auto spl_h {new QSplitter {}};
    spl_h->addWidget(wdg);
    spl_h->addWidget(new QGroupBox {"box 4"});
    spl_h->addWidget(new QGroupBox {"box 5"});
    splitter_handles {spl_h};

    auto h_lt {new QHBoxLayout {}};
    h_lt->addWidget(spl_h);

    QWidget w {};
    w.setLayout(h_lt);
    w.setGeometry(100,100,500,300);
    w.show();

    return a.exec();
}

-1
感谢Merula的回答...我尝试了这个方法,现在我的分隔符可见,并且看起来非常漂亮,而不会显得突兀。这段代码适用于使用PyQt或PySide的Python。
app = QtGui.QApplication(sys.argv)
app.setStyle("Plastique")   # set style (using this style shows splitters! :)

这是什么编程语言?它看起来不像C++。 - feedc0de
抱歉,这是使用PyQt或PySide的Python。 - panofish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接