QSplitter becoming undistinguishable between QWidget and QTabWidget

前端 未结 7 1107
庸人自扰
庸人自扰 2021-02-04 06:30

I am puting a QWidget and a QTabWidget next to each other in one horisontal splitter. And the splitter loses it\'s shape, you can know that there is a splitter only by hovering

相关标签:
7条回答
  • 2021-02-04 07:01

    Since the QSplitterHandle (which is what most people think of as the 'splitter') is derived from QWidget, you can add other widgets to it. Here is what I have done to solve this exact problem in the past:

    // 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);
    

    This adds a sunken line to the splitter handle. You can, of course, choose another style for the frame line or use something entirely different as the widget you add to the splitter handle.

    0 讨论(0)
  • 2021-02-04 07:08

    Call splitter_handles {} with the QSplitter you want to add handles to:

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

    Result:

    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();
    }
    
    0 讨论(0)
  • 2021-02-04 07:10

    Thanks to Merula's answer... I tried this and now my splitters are visible and look very nice without looking obtrusive. This code is for Python using PyQt or PySide.

    app = QtGui.QApplication(sys.argv)
    app.setStyle("Plastique")   # set style (using this style shows splitters! :)
    
    0 讨论(0)
  • 2021-02-04 07:17

    Here is the most useful Python implementation to make the splitters visible. The code is inspired from @francek 's c++ implementation. enter image description here

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    import sys
    
    class Handle(QWidget):
        def paintEvent(self, e=None):
            painter = QPainter(self)
            painter.setPen(Qt.NoPen)
            painter.setBrush(Qt.Dense6Pattern)
            painter.drawRect(self.rect())
    
    class customSplitter(QSplitter):
        def addWidget(self, wdg):
            super().addWidget(wdg)
            self.width = self.handleWidth()
            l_handle = Handle()
            l_handle.setMaximumSize(self.width*2, self.width*10)
            layout = QHBoxLayout(self.handle(self.count()-1))
            layout.setSpacing(0)
            layout.setContentsMargins(0,0,0,0)
            layout.addWidget(l_handle)
    
    class Window(QMainWindow):
        def setUI(self, MainWindow):
            self.splt_v = customSplitter(Qt.Vertical)
            self.splt_v.setHandleWidth(8)
            self.splt_v.addWidget(QGroupBox("Box 1"))
            self.splt_v.addWidget(QGroupBox("Box 2"))
            self.splt_v.addWidget(QGroupBox("Box 3"))
    
            self.wdg = QWidget()
            self.v_lt = QVBoxLayout(self.wdg)
            self.v_lt.addWidget(self.splt_v)
    
            self.spl_h = customSplitter()
            self.spl_h.addWidget(self.wdg)
            self.spl_h.addWidget(QGroupBox("Box 4"))
            self.spl_h.addWidget(QGroupBox("Box 5"))
    
            self.h_lt = QHBoxLayout()
            self.h_lt.addWidget(self.spl_h)
            self.w = QWidget()
            self.w.setLayout(self.h_lt)
            self.w.setGeometry(0,0,1280,720)
            self.w.show()
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        MainWindow = QMainWindow()
        ui = Window()
        ui.setUI(MainWindow)
        sys.exit(app.exec_())
    
    0 讨论(0)
  • 2021-02-04 07:22

    I based this on the above code but it handles both splitter orientations. I just preferred non-opaque resizing and non-collapsible children. The grip consists of three parallel lines. You can play with the handle width, but grip at 7 looks good on Windows; haven't checked in Linux or 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();
        }
    }
    
    0 讨论(0)
  • 2021-02-04 07:24

    This is true for every splitter at least with WinXP and the default Luna thema (changing to classic solves the problem). If you want to stay with Luna you may change the way the splitters are rendered, e.g. by changing the background color of the handle.

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

    You may find more on Qt style sheets at https://doc.qt.io/qt-5/stylesheet-reference.html

    0 讨论(0)
提交回复
热议问题