How to get font of widget in Qt set by stylesheet? - c++

I have Qt application with custom stylesheet applied to it (and for all widgets in general) with custom font included in this stylesheet. But when try to get font of some widget font() method return different font. I want to get the font of a QWidget which is set by a stylesheet. The font() method always returns the global system font or the font set by setFont(), but not the font which is set by setStyleSheet() and is used for painting in the widget. I need the font to do some calculations based on the font size. I use Qt 4.6. How can I get real font of widget (that is showing when application run) set by stylesheet?
After some investigations I saw that if I apply defined stylesheet to some widget I can get proper font information (defined by stylesheet) with myWidget->font() method. Also when I set stylesheet to whole MainWindow I can get proper font information with font() method for all the widgets that MainWindow contains. But, when I set stylesheet to instance of QApplication the font() method for all the widgets return default font or the font previously set by setFont(). Why so?

You can retrieve a font of a specific widget reading it's properties, as the following:
//Get pushbutton font.
QFont font = ui->pushButton->property("font").value<QFont>();
qDebug() << font.family() << font.pointSize();
//Get MainWindow font.
QFont font2 = property("font").value<QFont>();
qDebug() << font2.family() << font2.pointSize();

To load values from Qt Stylesheet you should call this methods:
widget->style()->unpolish(widget);
widget->style()->polish(widget);
widget->update();
After this all values of your widget will be updated according your stylesheet values specified.

The best I can tell from QStyleSheetStyle::updateStyleSheetFont, the widget always contains the resolved font from the stylesheet. I'd expect QWidget::font() to return the resolved font that you've set using the stylesheet - i.e. the font that is the merged application font, any parent widget fonts, and the stylesheet font.
The widget must be polished first, of course, unless you're querying after the events have been delivered (i.e. from within the event loop).
// https://github.com/KubaO/stackoverflown/tree/master/questions/style-font-query-test-45422885
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QLabel label("Test");
auto font1 = label.font();
label.setStyleSheet("font-size: 49pt;");
label.show();
label.ensurePolished();
auto font2 = label.font();
Q_ASSERT(font1.pointSize() != 49);
Q_ASSERT(font2.pointSize() == 49);
Q_ASSERT(font1.family() == font2.family());
}

Related

QPlainTextEdit set font for only one line

Is that possible to display text with different fonts with QPlainTextEdit?
i've tried this, but it seems that font changes for a moment for all widget and the returns to normal:
QFont font;
font.setBold(true);
ui->plainTextEdit->setFont(font);
ui->plainTextEdit->insertPlainText("Some text:\n");
font.setBold(false);
ui->plainTextEdit->setFont(font);
I've tried to change QPlainTextEdit to QTextEdit it didn't helped
QPlainTextEdit and QTextEdit both inherit setFont from QWidget, and a QWidget only has one font type at a time.
However, QTextEdit exposes an interface to set the font for different parts of the text via QTextCharFormat
In your case, the easiest way to fix this should be to use a QTextEdit, and the setCurrentFont method.
QFont font;
font.setBold(true);
ui->textEdit->setCurrentFont(font);
ui->textEdit->insertPlainText("Some text:\n");
font.setBold(false);
ui->textEdit->setCurrentFont(font);
(In this very specific case, you could also use setFontWeight to select bold/normal font, but for more general modifications setCurrentFont is more appropriate)

Qt set common background for all dialog boxes

I am working on developing a Qt 5 widgets desktop application where I want to give a common background for all windows and dialog boxes that pop up. The problem is that for each window I have to specify the same piece of code over and over again to load the same background. I am also using paint function override so as not to distort the background when window is resized. Here's my code:
SettingsDialog::SettingsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
pixmapBg.load(":/images/google-material-design-wallpaper-10.jpg");
}
void SettingsDialog::paintEvent(QPaintEvent *pe)
{
QPixmap pixmapBgL = pixmapBg.scaled(this->size());
QPalette palette;
palette.setBrush(QPalette::Background, pixmapBgL);
this->setPalette(palette);
}
Is there a way to accommodate this in Qt using a single file rather than mentioning it for each window?
Yes, you can! You will have to provide your own stylesheet, or initialize your application by calling QApplication::setStyleSheet(styleName).
Follow up from comment: setStyleSheet is the quickest approach, i.e.
qApp->setStyleSheet("QDialog, QMessageBox {background-image: url(:/images/google-material-design-wallpaper-10.jpg);}");
assuming you have a valid QApplication reference qApp. Note that you can also refer to your custom subclasses as well, if you want to refine the scope of the stylesheet.
Here is some code using QApplication::setStyleSheet:
QString styleSheet = "QWidget{\
background-color: yellow\
}"//style sheet in CSS style
int main(int argc, char** argv){
QApplication app(argc, argv);
app.setStyleSheet(styleSheet);//will set all the QWidgets' background color to yellow
return app.exec();
}
There is actually a background-image property but I'm not sure about which widgets are supporting it so you can check right there.

How do I just put header and some content under it in Qt Designer?

QtCreator's designer allows you to edit user interface graphically. I was just trying to make some sense of it - what I wanted was a header text centered in the middle and some widget under it, like this:
But my results look like this, when using vertical layout:
I placed QLabel on top and QOpenGLWidget on bottom - I only used QOpenGlWidget because it has black background on screenshot. What I really plan on doing is using another QWidget. I used vertical layout then. So how do I get the result on the first image, using QLabel and QWidget?
Qt's use of XML is not a replacement for HTML.
HTML is designed for marking up web pages. Qt's widgets are not web pages!
It appears that you're looking at the box with the text 'content' and thinking of a generic widget. I see that and see a QLabel, which is derived from QWidget after all.
It's probably easier to explain in code how I would go about this, which you can then translate to doing the same in Qt Creator.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Create a root widget (this could also be a QMainWindow, or any other widget)
QWidget* pWidget = new QWidget;
// Layout to arrange the widgets vertically
QVBoxLayout* pBoxLayout = new QVBoxLayout;
pWidget->setLayout(pBoxLayout);
// The header widget
QLabel* pHeader = new QLabel("Header");
pHeader->setAlignment(Qt::AlignCenter);
pHeader->setMinimumSize(200, 20);
pHeader->setMaximumSize(200, 20);
QFont font = pHeader->font();
font.setBold(true);
font.setPixelSize(16);
pHeader->setFont(font);
// the content widget
QLabel* plabel = new QLabel("content");
plabel->setMinimumSize(200, 200);
plabel->setMaximumSize(200, 200);
plabel->setStyleSheet("background-color: rgb(182, 182, 182); border: 5px solid black;");
plabel->setAlignment(Qt::AlignCenter);
pBoxLayout->addWidget(pHeader);
pBoxLayout->addWidget(plabel);
pWidget->show();
return a.exec();
}
As you can see here, I've styled the content widget with the use of a Style Sheet. This is really the easiest method, after a bit of practice with them.
The resulting code produces a widget which looks like this: -
You can play with dimensions and fonts to match your original image exactly.

Change color highlight of icons in QTableView, when the cell is selected

When a cell is selected in QTableView, the icons in it are given a blue highlight, how can I control the color of this highlight or disable it?
I tried setting the QPalette::Highlight but it didn't work.
Edit:
Okay, so I do know how to change the background color and text color and color highlight, but not for an icon. If I return an icon as decoration for a cell, it is given a light blue highlight when the cell is selected. How do I remove this?
You can use style sheets to define the color of your elements. The name of the selected item in your QTableView is selection-background-color. So, changing the color of this element you will chose the background color that your prefer.
#include <QtWidgets/QApplication>
#include <QtWidgets/QTableView>
#include <QStandardItemModel>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QTableView *table = new QTableView();
QStandardItemModel *model = new QStandardItemModel(2,2);
table->setModel(model);
table->setStyleSheet("selection-background-color: red");
table->show();
return app.exec();
}
Look how it looks in the picture:
I discovered a way around this issue, but it has some cost associated with it.
Fundamentally, deep within Qt code it is calling onto QIcon::paint() and passing QIcon::Selected as the icon mode, so the issue is that the "selected" form of the icon's pixmap at the desired resolution is the one auto-generated by Qt.
I worked around this by setting the Selected form of the icon to be the same as the Normal mode:
// Make the "Selected" version of the icon look the same as "Normal".
for (const auto& size : icon.availableSizes())
{
icon.addPixmap(icon.pixmap(size, QIcon::Normal, QIcon::Off),
QIcon::Selected, QIcon::Off);
icon.addPixmap(icon.pixmap(size, QIcon::Normal, QIcon::On),
QIcon::Selected, QIcon::On);
}
The downside is extra time spent doing this, possibly extra memory to store it, and wasted time generating the selected icons that we're throwing away.
In my case I'm using a QStyledItemDelegate and unfortunately that doesn't give you the ability to more closely influencing how the icon is rendered without completely reimplementing how QStyle::CE_ItemViewItem is rendered in your style.
Come to think of it, if you use a proxy style it wouldn't be too hard to override how CE_ItemViewItem is rendered to not use a selected icon, so that would be an option too.
It's utterly impossible to change this behavior with the standard style in Qt. You need to implement your own specific style in order to work around this.

Display QImage within main window

I'm trying to display an image with Qt, I can get it to appear in a separate window, but I can't make it appear within the main window
Qt_first w;
w.show();
This shows the window I designed in Qt designer, how do I access the Qlabel(Image_Lbel) I put within the QWidget (centralWidget) of that window?
I generated a stripy image that shows correctly, just not within the correct window
QSize size = QSize(640,480);
QImage::Format format = QImage::Format_ARGB32;
QImage image = QImage::QImage(size, format);
//generate
QLabel myLabel;
myLabel.setPixmap(QPixmap::fromImage(image));
myLabel.show();
I get the feeling it could be I haven't included the files from the creator or the namespaces any suggestion much appreciated
I guess your Label is getting displayed independently. Set the parent of label to your main window. Then your Label will displayed inside your main window.
So use,
QLabel *myLabel = new QLabel(this); // sets parent of label to main window
myLabel->setPixmap(QPixmap::fromImage(image));
myLabel->show();
You can also use move function for moving your label within the main window.
If you want to set the label from outside the Qt_first class, you need to add a method to do this. For example (in qt_first.cpp, change qt_first.h accordingly):
void Qt_first::setImageLabel(const QImage& image)
{
ui->Image_Lble.setPixmap(QPixmap::fromImage(image));
}
ui in this example is the object that represents the UI that you created with Qt Designer.
I used a combination of both answers, thanks to both
Qt_first w; // the UI I made with Qt creator
QLabel *myLabel = w.getImageLabel();
myLabel->setPixmap(QPixmap::fromImage(image));
w.show();
With the following inside the Qt_first class
QLabel* Qt_first::getImageLabel(){
QLabel *myLabel = ui.Image_Label;
return myLabel;
}