Increase QTabWidget tab size while using custom palette - css

My app uses a QTabWidget. I want the tabs to fill the entire length of the tab bar.
My app also uses a palette to set the colors of all widgets, forms, etc.
I found that I can set the tab size as intended like so:
ui->tabWidget->setStyleSheet(QString("QTabBar::tab { width: %1px; }").arg(ui->tabWidget->size().width()/ui->tabWidget->count()));
But this causes the tab widget and all of its children to ignore my palette.
How can I use my palette and also increase the tab size?

I tried to reproduce your described behavior, but I was not able to do so. I'm using Qt 5.13.0, maybe it is in older version. At first I also thought, that I reproduced your behavior, but then I recognized, that I just didn't fully understood the options in QPalette, which really has a lot of ColorGroups and ColorRoles with different meanings.
Try the following simple test runner in order to verify it with your Qt Version.
#include <QApplication>
#include <QTabWidget>
#include <QFrame>
#include <QHBoxLayout>
#include <QPushButton>
int main(int argc, char** args) {
QApplication app(argc, args);
auto p=app.palette();
p.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::Background, QColor("red"));
p.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::Foreground, QColor("blue"));
p.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::ButtonText, QColor("magenta"));
app.setPalette(p);
auto w= new QTabWidget;
auto f=new QFrame;
f->setLayout(new QHBoxLayout);
f->layout()->addWidget(new QPushButton("Test"));
w->addTab(f,"Tab1");
w->setStyleSheet(QString("QTabBar::tab { width: %1px; height: %1px }").arg(100));
w->show();
app.exec();
}

Related

QPainter's drawGlyphRun not rendering anything on QPixmap

in order to create a LaTeX rendering engine from scratch (including both simple text and math formulas, with AMS math glyphs stored in TrueType font files), following Qt classes has been chosen to draw a glyph on given position: QRawFont, QGlyphRun, QPainter, QPixmap.
However, snippet below based on them does NOT render anything. In principle, it should
load glyphs from a True Type font file using QRawFont class
render a glyph on a QPixmap using QPainter and its drawGlyphRun() function
Here goes the snippet:
#include <QGuiApplication>
#include <QPixmap>
#include <QPainter>
#include <QGlyphRun>
#include <QRawFont>
int main(int argc, char* argv[]){
QGuiApplication app(argc, argv);
QRawFont math_raw_font(QString("cmmi10.ttf"), 10, QFont::PreferDefaultHinting);
QVector<quint32>* my_glyphs = new QVector<quint32>;
my_glyphs->push_back(10);
QGlyphRun math_glyph_run;
math_glyph_run.setRawFont(math_raw_font);
math_glyph_run.setGlyphIndexes(*my_glyphs);
math_glyph_run.setBoundingRect(QRectF(0,0,200,200));
QPixmap img(200, 200);
img.fill(Qt::white);
QPainter my_painter(&img);
my_painter.setPen(Qt::red);
my_painter.drawGlyphRun(QPointF(100,100), math_glyph_run);
auto ok = img.save("output.png");
return 0;
}
So far, I have
verified validity of the TTF file using QRawFont's isValid() function and Ubuntu's font manager using command font-manager cmmi10.ttf
verified glyphs using QGlyphRuns's glyphIndexes()
verified valid rendering system using QPainter's drawText() function, which works OK
I have already read Qt documentation. I will be gratefull for any tip or advice.

Would that be possible to build a particular customized QPushButton?

I was trying to understand if there is a way to build a particular customized QPushButton?
What I am trying to achieve is the following layout and appearance:
The button is shown below, notice the red line (which meas that the button is not clicked). I am not sure how to achieve the red line. I think it could be widget? or a QProgressbar, that when is clicked goes/loads up to green..I am not sure because I don't have enough experience and have been trying to build it. However this seems to be a bit tough:
And below how it should look like right after the click happened (note the green line):
Despite my efforts, I found some useful sources that I could use to get me started: for example this source was great to understand how to start. I studied the fact that in order to achieve that, the button need to be subclassed, and that is great because it lays some sort of route.
Below the code I used:
custombutton.h
#ifndef CUSTOMBUTTON_H
#define CUSTOMBUTTON_H
#include <QPushButton>
class CustomButton : public QPushButton
{
public:
CustomButton( const QString& text, QWidget* parent = 0 );
void writeText();
};
#endif // CUSTOMBUTTON_H
custombutton.cpp
#include "CustomButton.h"
#include "algorithm"
CustomButton::CustomButton( const QString& text, QWidget* parent )
: QPushButton( text, parent )
{
}
void CustomButton::writeText()
{
QString buttonText = text();
setText( buttonText );
}
main
#include <QApplication>
#include "CustomButton.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CustomButton w( "MyButton" );
w.show();
w.writeText();
a.exec();
return 0;
}
Another useful source I found is this one which also was useful.
The official documentation points to use the styles, but I am trying not to do that because I would like to solve the problem understanding what is the potential of subclassing with Qt.
Unless going in the style direction is the only possible way to solve this problem?
I would like to thank anyone in advance for sharing or pointing to a potential solution on how to do that.
You can set your button as checkable and then set a different icon for the 2 states.
In your case you'd have to set the red icon for the Normal mode and the green one for the Selected mode
Here's an example:
https://www.dropbox.com/s/x40byuyu2ph8m1y/CheckableButton.zip?dl=0
Here someone asked the same thing:
https://forum.qt.io/topic/72363/change-icon-of-pushbutton
Here you can read abouth the modes:
https://doc.qt.io/qt-5/qicon.html#Mode-enum
PS: Of course overriding QAbstractButton::paintEvent(QPaintEvent *event) is a viable option too

Restore geometry and state of an arbitrary QDialog

In our applications we are using customizable dialogs using exhaustively QSplitter, so that our customers can rearrange the dialogs to fit their needs.
(Sometimes we are also using QDockWidget, but this seems to be similar.)
Now, it is very annoying to rearrange the dialog every time it is opened again. Or even between different starts of the program.
After consulting the documentation I was able to restore the state and the geometry of a specific dialog containing one QSplitter.
#include <QApplication>
#include <QLabel>
#include <QDebug>
#include <QSplitter>
#include <QPushButton>
#include <QTextEdit>
#include <QDialog>
#include <QSettings>
#include <QHBoxLayout>
int main(int argc, char** args) {
QApplication app(argc, args);
app.setOrganizationName("Tech");
app.setOrganizationDomain("qt.us");
app.setApplicationName("RestoreLayout");
app.setApplicationVersion("1.0");
QDialog dialog;
dialog.setLayout(new QHBoxLayout);
auto splitter = new QSplitter;
splitter->addWidget(new QLabel("Left"));
splitter->addWidget(new QLabel("Right"));
dialog.layout()->addWidget(splitter);
auto accept = new QPushButton("Accept");
accept->connect(accept, &QPushButton::clicked, [&](){
dialog.accept();
});
splitter->addWidget(accept);
auto geom= QSettings().value("Geom").toByteArray();
auto splitterState = QSettings().value("State").toByteArray();
qDebug() << geom;
qDebug() << splitterState;
dialog.restoreGeometry(geom);
splitter->restoreState(splitterState);
dialog.show();
dialog.connect(&dialog, &QDialog::accepted, [&]() {
QSettings().setValue("Geom", dialog.saveGeometry());
QSettings().setValue("State", splitter->saveState());
app.quit();
});
app.exec();
}
Unfortunately, this seems to be an approach, which is not usable in general.
Assume, that there is some arbitrary dialog, that needs to restore its geometry and state. Even worser QSplitter and QDockWidget might be even used in a nested fashion, which is done in our applications.
How can an outside programmer restore the geometry and the state of a arbitrary dialog that might be easily applicable to all possible dialogs?
For saving states of QDockWidget each it must be named: dockWidgetN->setObjectName("dock-widget-N");
But you can save only QMainWindow state for saving states of docks in this window.
You can separatelly save states via QSettings (it's QByteArray) and use some one state for many windows.
See here: How to save state of a dialog in Qt?

Styled top-level QPushButton widget does not render properly

I've successfully made a QPushButton the top-level widget/window of an application and am attempting to style the button like so:
#include <QPushButton>
#include <QApplication>
class MyButton : public QPushButton
{
public:
MyButton() : QPushButton( "Button" )
{
setFixedSize( 250 , 65 );
setStyleSheet( "border-radius: 10px;" ); // style
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyButton b;
b.setWindowFlags( Qt::FramelessWindowHint | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint );
b.setAttribute(Qt::WA_TranslucentBackground); // Fixes opaque BG
b.show();
return a.exec();
}
Unfortunately, as the following image shows, the button is no longer rendered properly when the style is applied. I'd appreciate help getting the button to render the style properly.
Edit
Following Kuber Obas answer, I'd appreciate help styling the edges of the widget, i.e. those that are outside the rounded corner, to transparent as shown below
In most native styles, the border is drawn with the rest of the button using native functionality and its elements cannot be replaced one-by-one. Once you introduce your own styling, the monolithic native styling is gone. So, you'll need to replace all of the functionality provided by the native style, including the border, the background gradient, etc. You will need to tweak it to "match" native style if you so need.
Here, you need to redefine the border completely: at the minimum provide the pen (border:). The radius only makes sense with the pen. You also need to redefine the background, if you care for one, redefine all of the button's state selectors, etc. You start with an unstyled button!
The screenshot below demonstrates it well. On the left you have a Mac-styled native button, on the right you have a button with just its border defined anew. It's obvious that the default state background should also be adjusted to match that of the platform in this case, and some margin needs to be added.
Qt doesn't really re-do modern native styles entirely from scratch, that's why you can't tweak their individual elements. It'd be too much work and a constantly moving target. It used to be done for the old Windows-95/NT style. Starting with the XP style, it was decided to let the platform APIs provide the visual style bitmaps. Similar thing presumably happens on OS X. That's also the reason why you can't use the fancier XP/Aqua/Mac Qt styles outside of their native platform: the relevant native APIs are not present and thus the style is disabled.
// https://github.com/KubaO/stackoverflown/tree/master/questions/styledbutton-20642553
#include <QPushButton>
#include <QHBoxLayout>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a{argc, argv};
QWidget w;
QHBoxLayout layout{&w};
QPushButton button1{"Default"};
button1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
layout.addWidget(&button1);
QPushButton button2{"Styled"};
button2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
button2.setStyleSheet(
"* { border: 2px solid #8f8f91; border-radius: 12px; background-color: #d02020; }"
"*:pressed { background-color: #f6f7fa; }");
layout.addWidget(&button2);
auto pal = w.palette();
pal.setBrush(QPalette::Background, Qt::darkBlue);
w.setPalette(pal);
w.show();
return a.exec();
}

Qt MDI Area subwindow construction after show->() fails to update window size

I have a program that constructs a subwindow in a QT MDI Area, shows it, and later updates the contents of this window.
The program is large, but I have tried (and hopefully succeded) to reproduce the problem in the little program below.
In the middle of the program, there is the line commented "if this one is commented, then OK!".
As it says, if this line is commented, then the whole subwindow contents is created before Qt goes into the event loop and everything is fine...
BUT: is the line is there, then the contents of the MDI subwindow is constructed in 2 steps (as in my original program), but only the contents built in the first step shows up!
Run the little program below...
...if you now grab the sub-window (with the mouse), to move it, then Qt suddentely realize the size is wrong and updates the subwindow contents...
I could not figure out any way to get that correctly from start.
I am running Qt 4.8.0-7 on linux (Fedora).
#include <QApplication>
#include <QtCore>
#include <QMainWindow>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <stdlib.h>
QMdiArea* g1;
QGroupBox* g1a;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow* main_window = new(QMainWindow);
main_window->setObjectName("main_window");
main_window->resize(200, 200);
main_window->setWindowTitle("Hello");
g1 = new QMdiArea(main_window);
main_window->setCentralWidget(g1);
main_window->show();
g1a = new QGroupBox("G1A", g1);
QVBoxLayout *g1a_l = new QVBoxLayout(g1a);
g1a_l->addWidget(new QLabel("LABEL1"));
QMdiSubWindow *sub_window = new QMdiSubWindow(g1);
sub_window->setWidget(g1a);
sub_window->setAttribute(Qt::WA_DeleteOnClose);
app.processEvents(); //If this one is commented, then OK!
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label2"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label3"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label4"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label5"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label6"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label7"));
sub_window->show(); //How to I get that to recaclulate the size of its contents?
return app.exec();
}
Thanks for helping!
Use adjustSize method:
sub_window->show(); // here or after adjustSize
sub_window->adjustSize();
It will adjust the size to fit sub_window contents (from documentation).

Resources