Propagation and use of Stylesheets for QSplitter Handle



  • I am trying to use Stylesheets in Qt to create the look I want for my QSplitters. Unfortunately, the behavior is not what I expect. Am I doing it wrong, or did I encounter a bug in Qt? How should I be doing what I'm trying to do?

    I wrote up a simple app (I went a little overboard with the generalization, but I was having fun, so sue me) to demonstrate the issue I'm having. All of the code is in the mainwindow.cpp, so if you have the QtCreator installed (I'm using version 5.3.2), you just need to create a new QtWidgetsApplication and dump the code into mainwindow.cpp.

    To start with, here are the stylesheets I've been playing with:

    const QString splitterSheetH =  \
    "QSplitter::handle:horizontal {	\
    	border: 3px dashed blue;	\
    	margin: 50px 1px;			\
    }";
    
    const QString splitterSheetV =  \
    "QSplitter::handle:vertical {	\
    	border: 3px dashed black;	\
    	margin: 1px 50px;			\
    }";
    
    const QString splitterSheet = splitterSheetH + splitterSheetV;
    

    My understanding is that QSplitter::handle:horizontal is supposed to apply to those with horizontal orientation, and the similarly for QSplitter::handle:vertical. However, no matter how I change the sheet order, widget nesting, etc, the handles of the horizontal QSplitters all seem to have some ghost property setting the minimum width using the vertical's margins and ignoring their own, despite actually rendering with the proper margin of (50px,1px).

    Here is what it looks like when you run it. The intention was to use the Margins to offset the handle's borders significantly on the major axis. To that end, margin is working properly, except for how the size of both orientations seems to be determined using the margins of the Vertical's stylesheet. Is this my problem, Qt's issue, or perhaps both?

    #include <QVBoxLayout>
    #include <QHBoxLayout>
    #include <QSplitter>
    #include <QFrame>
    #include <QString>
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #define BOTTOM_FRAME_NUM 7
    #define LOWER_SPLITTER_NUM 3
    
    #if !defined(LOWER_SPLITTER_NUM) || LOWER_SPLITTER_NUM < 2
    	#error LOWER_SPLITTER_NUM must be greater than or equal to 2.
    #endif
    
    #if !defined(BOTTOM_FRAME_NUM) || BOTTOM_FRAME_NUM < LOWER_SPLITTER_NUM
    	#error BOTTOM_FRAME_NUM must be greater than or equal to LOWER_SPLITTER_NUM.
    #endif
    
    const QString splitterSheetH =  \
    "QSplitter::handle:horizontal {	\
    	border: 3px dashed blue;	\
    	margin: 50px 1px;			\
    }";
    
    const QString splitterSheetV =  \
    "QSplitter::handle:vertical {	\
    	border: 3px dashed black;	\
    	margin: 1px 50px;			\
    }";
    
    const QString splitterSheet = splitterSheetH + splitterSheetV;
    
    int getLowerSplitterDivisor(int index);
    
    MainWindow::MainWindow(QWidget *parent) :
    	QMainWindow(parent),
    	ui(new Ui::MainWindow)
    {
    	ui->setupUi(this);
    	resize(800,800);
    
    	//Create central widget
    	QWidget *centralWidget = new QWidget(this);
    	centralWidget->setStyleSheet("background-color: white;");
    
    	//------ Setting the Stylesheet so it propagates ------
    	centralWidget->setStyleSheet(splitterSheet);
    	//centralWidget->setStyleSheet(splitterSheetV);
    	//centralWidget->setStyleSheet(splitterSheetH);
    
    	setCentralWidget(centralWidget);
    	centralWidget->setLayout(new QVBoxLayout());
    
    	//------ Splitters for testing ------
    	QSplitter *vertSplitter = new QSplitter(Qt::Vertical);
    	QSplitter *horizSplitter = new QSplitter(Qt::Horizontal);
    
    	QSplitter *splitterArray[LOWER_SPLITTER_NUM];
    	QList<Qt::Orientation> orientationList = QList<Qt::Orientation>() << Qt::Vertical << Qt::Horizontal;
    	for (int i = 0; i < LOWER_SPLITTER_NUM; i++)
    	{
    		splitterArray[i] = new QSplitter(orientationList[i%orientationList.count()]);
    	}
    
    	//------ Bottom Frames ------
    	QFrame *newFrame;
    	QList<QString> colors = QList<QString>() << "silver" << "gray" << "blue" << "red";
    	QList<int> lowerSplitterSizes[LOWER_SPLITTER_NUM];
    	for ( int i = 0; i < BOTTOM_FRAME_NUM; i++)
    	{
    		newFrame = new QFrame();
    		newFrame->setStyleSheet(QString() + "background-color: " + colors[i%colors.count()] + "; border: 2px solid black; border-radius: 10px;");
    		splitterArray[i%LOWER_SPLITTER_NUM]->addWidget(newFrame);
    		lowerSplitterSizes[i%LOWER_SPLITTER_NUM] << 400/getLowerSplitterDivisor(i);
    	}
    
    	QList<int> horizSplitterSizes;
    	for (int i = 0; i < LOWER_SPLITTER_NUM; i++)
    	{
    		 horizSplitter->addWidget(splitterArray[i]);
    		 splitterArray[i]->setSizes(lowerSplitterSizes[i]);
    		 horizSplitterSizes << 800/LOWER_SPLITTER_NUM;
    	}
    
    	//------ Top Frame ------
    	QFrame *topFrame = new QFrame();
    	topFrame->setStyleSheet("background-color: maroon; border: 3px solid black; border-radius: 10px;");
    	vertSplitter->addWidget(topFrame);
    	vertSplitter->addWidget(horizSplitter);
    
    	//Setting default size
    	vertSplitter->setSizes(QList<int>() << 400 << 400);
    	horizSplitter->setSizes(horizSplitterSizes);
    
    	centralWidget->layout()->addWidget(vertSplitter);
    
    }
    
    int getLowerSplitterDivisor(int index)
    {
    	return (BOTTOM_FRAME_NUM/LOWER_SPLITTER_NUM + (BOTTOM_FRAME_NUM%LOWER_SPLITTER_NUM)/(1 + index%LOWER_SPLITTER_NUM));
    }
    
    MainWindow::~MainWindow()
    {
    	delete ui;
    }
    

    Any assistance would be appreciated. Thanks!



  • Alright, I've solved my issue. It seems there were a couple things not behaving the way I thought. There still seems to be an underlying issue, but I have my workaround.

    This stylesheet solves the problem:

    const QString splitterSheetH =			\
    "QSplitter[orientation=\"1\"]::handle {	\
    	border: 3px dashed blue;			\
    	margin: 50px 1px;					\
    	min-width: 10px;					\
    	max-width: 10px;					\
    }";
    
    const QString splitterSheetV =			\
    "QSplitter[orientation=\"2\"]::handle {	\
    	border: 3px dashed black;			\
    	margin: 1px 50px;					\
    	min-height: 10px;					\
    	max-height: 10px;					\
    }";
    

    Whereas, curiously, this one draws improperly:

    const QString splitterSheetH =	\
    "QSplitter::handle:horizontal {	\
    	border: 3px dashed blue;	\
    	margin: 50px 1px;			\
    	min-width: 10px;			\
    	max-width: 10px;			\
    }";
    
    const QString splitterSheetV =	\
    "QSplitter::handle:vertical {	\
    	border: 3px dashed black;	\
    	margin: 1px 50px;			\
    	min-height: 10px;			\
    	max-height: 10px;			\
    }";
    

    It works, but I still really get the impression that the second one failing to work is a bug.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Reading the documentation about customizing QSplitter, it seems indeed that there's something not right going on. You should check the but report system to see if it's something known. If not, please consider opening a new report providing a minimal compilable example reproducing the behavior (well in this case the lack of it)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.