Can QMessageBox::about adjust size to title length? - qt

I wanted to create a simple About dialog, but noticed that the QMessageBox::about does not adjust its size to the length of the title (which is usually longer due to the larger font ...at least in my desktop environment), only to the content. Is there a way to make sure that the dialog is made big enough to show all of the title as well? I could of course add white space to the aboutText, but I am hoping for a less hackish solution.
Example:
QString titleText("Some title which is slightly longer");
QString aboutText("Short about text");
QMessageBox::about(this,titleText,aboutText);
Currently the above code only gives me "Some ..." as the title string. I have built the program in Eclipse on Ubuntu with Qt 4.7.

Use "setStyleSheet()" function of "QMessageBox". Here is an example.
background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #787878, stop: 0.5 #404040, stop: 0.6 #303030, stop: 0.8 #252525, stop: 1 #151515);
border: 2px solid #05b8cc;
border-radius: 8px;
color: white;
min-width: 300px;
min-height: 80px;
It will also affect the children of the "QMessageBox" whose stylesheets can be reverted by iterating through them. To access the children use "findChildren(QWidget)".

I believe QMessageBox does adjust size to fit the window title, but for some reason it doesn't work right on my system also, not sure if it's a bug or a feature, this is done in the qmessagabox.cpp QMessageBoxPrivate::updateSize() method.
Another thing I've noticed is that you're using an instance of the QMessageBox class to call about() method, which is static and you can execute it by using just the class name: QMessageBox::about(..).
What you could do to adjust the window size is creating your own subclass of the QMessageBox and adjusting min width of the window in the showEvent method, see the example below for details:
class MyMessageBox : public QMessageBox
{
public:
explicit MyMessageBox(QWidget *parent = 0) : QMessageBox(parent) { }
MyMessageBox(const QString &title, const QString &text, Icon icon,
int button0, int button1, int button2,
QWidget *parent = 0,
Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint) :
QMessageBox(title, text, icon, button0, button1, button2, parent, f) { }
static void about(QString title, QString text)
{
MyMessageBox aboutBox(title, text, QMessageBox::Information, 0, 0, 0, NULL);
aboutBox.setText(title);
aboutBox.setText(text);
QIcon icon = aboutBox.windowIcon();
QSize size = icon.actualSize(QSize(64, 64));
aboutBox.setIconPixmap(icon.pixmap(size));
aboutBox.exec();
}
void showEvent(QShowEvent *event)
{
QMessageBox::showEvent(event);
QWidget *textField = findChild<QWidget *>("qt_msgbox_label");
if (textField != NULL)
{
// getting what ever my system has set for the window title font
QFont font = QFont("Ubuntu Bold", 11);
// you might want to make it more generic by detecting the actuall font
// or using smth like this:
//QFont font = QApplication::font("QWorkspaceTitleBar");
QFontMetrics fm(font);
int width = qMax(fm.width(windowTitle()) + 50, textField->minimumWidth());
textField->setMinimumWidth(width);
}
}
};
here's how you can call it:
QString titleText("Some title which is slightly longer");
QString aboutText("Short about text");
MyMessageBox::about(titleText, aboutText);
hope this helps, regards

Related

Drawing rectangle line-by-line doesn't have the same result as drawing it directly

I'm trying to customize the borders of the cells in a (custom) QTableView. To do that, I found this:
class MyDelegate : public QItemDelegate {
public:
MyDelegate( QObject *parent ) : QItemDelegate( parent ) { }
void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const {
QItemDelegate::paint( painter, option, index );
if( /* some condition */ ) {
painter->setPen( Qt::red );
painter->drawRect( option.rect );
}
}
}
This works well. I added this in my delegate - which already has a custom paint method for other things and it does exactly what I want:
Neat.
Things start to go rogue when I want to decide what borders I actually draw. To do this, each item has a BorderOption property, which describes what borders should be draw. And my grid isn't 1px large anymore.
So what I decided to try out was the following:
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
Which should have the same result, right? Right? Well... no.
It seems like two 1px-width lines are being drawn, one for each cell.
That could make sense, if the cells' rectangles didn't overlap. But we've seen before it is not the case, as the first example worked and produced rectangles of width 1px.
Am I doing something wrong?
Thanks
I think there is a misconception on the meaning of option.rect. It is really the rectangle of the item of the table. There is still a portion, a one pixel wide line, that does not belong to the option.rect of the item, but to the QTreeView itself.
This becomes more visible if you restrict the drawing to the allowed item portion by setting setClipRect and by making the lines distinguishable using different colors.
Try to experiment with the width of the drawn line and by enabling and disabling the clip rect. Maybe you need to draw outside of the allowed option.rec, but be aware that you have to consider also different drawings of QTreeView on different platforms, where the separating lines might be 0px wide or wider than just one pixel.
#pragma once
#include <QStyledItemDelegate>
#include <QItemSelectionModel>
#include <QPainter>
#include <QDebug>
class MyDelegate : public QStyledItemDelegate {
public:
MyDelegate(QObject* parent=nullptr) : QStyledItemDelegate(parent) { }
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QStyledItemDelegate::paint(painter, option, index);
if (true) {
painter->save();
auto color=QColor::fromHsv((30*index.row() + 30 * index.column()) % 255, 255, 127);
painter->setPen(QPen(color, 1, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
painter->setClipRect(option.rect); // Rectangle of the item
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
painter->restore();
}
}
};
Did you tried to set thickness of the pen manually?
painter->setPen(QPen(QColor(255, 0, 0), 3, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
Here, I set the thickness to the 3px for example!

QLabel change font color without changing any other style

I want to change the color of the text in a QLabel dynamically.
I have defined the color and style of the QLabel in the ui file and I want to change it when a certain event takes place.
I want to change the color without changing any other style of my QLabel.
I have found several answers adressing the issue of changing text color in a QLabel (1, 2, 3) and they all use the function setStyleSheet. This function works fine but it changes my font size and other styles related to the QLabel.
I have seen that the problem is related to setStyleSheet ignoring any previous style. The solution proposed there involves retrieving all the styles I want to maintain and setting them again together with the text color change.
This is cumbersome and difficult to maintain. If more styles were defined in the future I would need to review this part of the code to be able to reset all of them.
I would like to be able to change QLabel text color without altering any other syle. Is it possible?
If you want to manage the text color of QLabel you could wrap it with customized class.
For example:
class ColorLabel : public QLabel
{
public:
ColorLabel(const QString &text, QWidget *parent = nullptr)
: QLabel(text, parent)
{
setAutoFillBackground(true);
}
void setTextColor(const QColor &color)
{
QPalette palette = this->palette();
palette.setColor(this->backgroundRole(), color);
palette.setColor(this->foregroundRole(), color);
this->setPalette(palette);
}
};
And to use it in your code:
ColorLabel * poColorLabel = new ColorLabel("My string", this);
poColorLabel->setTextColor(Qt::red); // set label text in red color
FYI: I tested it on Fedora, Qt5.12 and it works fine.
A pragmatic approach:
Utilize the cascadingness of CSS.
Wrap your QLabel in a QWidget (don't forget a QLayout).
Set your default style on the surrounding QWidget.
Set the font color as the QLabel's only style.
You can create some style class to control a widget's style:
class WidgetStyleSheet
{
public:
// change some style's value
void setValue(const QString& styleKey, const QString& value)
{
_styleMap[styleKey] = value;
}
// to default state
void reset() {}
// form stylesheet
QString toStyleSheet() const
{
QString styleSheet;
QMapIterator<QString, QString> iter(_styleMap);
while( iter.hasNext() )
styleSheet += QString("%1: %2").arg(iter.key()).arg(iter.value());
return styleSheet;
}
private:
QMap<QString, QString> _styleMap;
}
Somewhere in your code:
WidgetStyleSheet labelSS;
// ...
labelSS.setValue("color", QString("%1").arg( QColor(255, 10, 0).name() );
labelSS.setValue("background-color", "...");
// ...
label->setStyleSheet(labelSS);
The following works fine. But it is not that elegant. This is in python. You have to pass the button name (or any other) to the following as is defined in the array
btns = ['self.hBeamBtn','self.lBeamBtn','self.allTestBtn','self.prnStatusBtn']
for btn in btns:
if str(btn_name) == str(btn):
styl = btn+'.setStyleSheet("font: bold;background-color: red;font-size: 12px;height: 28px;width: 80px;")'
eval(styl)

How to place an icon onto a QLineEdit?

There is a Search field with the magnification-lens and a greyed out "search" keyword at the top right corner of stackoverflow.com web site:
I wonder if it is possible to achieve a same appearance with QLineEdit. If so then how?
QLineEdit* _lineEdit = new QLineEdit();
_lineEdit->setClearButtonEnabled(true);
_lineEdit->addAction(":/resources/search.ico", QLineEdit::LeadingPosition);
_lineEdit->setPlaceHolderText("Search...");
extracted from: http://saurabhg.com/programming/search-box-using-qlineedit/
Simple Way for Dummies
Add a QLineEdit, and set it frameless by QLineEdit::setFrame
Add a QLabel with background color in white (by stylesheet) and a icon
Combine the line edit and the label with a layout, set spacing to 0
Set placeholder text with QLineEdit::setPlaceholderText
Result
Advanced Way
Check this thread: "Can QLineEdit do this?"
And the related python code: http://bazaar.launchpad.net/~henning-schroeder/%2Bjunk/qtwidgets/annotate/head:/qtwidgets/lineedit.py
Or
"How to do - inside in QLineEdit insert the button.[pyqt4]"
Basically customized a QLineEdit by painting a widget(label, button or even combobox) onto it. Then reset the margin, cursor, padding and the paint event. No magics!
Here is an alternate simple way:
Set the placeholderText to "🔍" and the font Family to Seqoe UI Symbol or other font that can be found on your target systems that include the U+1F50D LEFT-POINTING MAGNIFYING GLASS glyph.
Here's a way to achieve this with stylesheets only:
QLineEdit {
background: #f3f3f3;
background-image: url(:Images/search.svg); /* actual size, e.g. 16x16 */
background-repeat: no-repeat;
background-position: left;
color: #252424;
font-family: SegoeUI;
font-size: 12px;
padding: 2 2 2 20; /* left padding (last number) must be more than the icon's width */
}
Here's the result:
It's still not perfect. You don't have much influence over the icon's position.
To have a result like this:
You can subclass the QLineEdit.
So your header should look something like this:
#ifndef LINEEDITICON_H
#define LINEEDITICON_H
#include <QLineEdit>
#include <QIcon>
class LineEditIcon : public QLineEdit
{
Q_OBJECT
public:
LineEditIcon(const QIcon icon, QWidget *parent = Q_NULLPTR);
~LineEditIcon();
void setIcon(QIcon icon);
protected:
virtual void paintEvent(QPaintEvent *event);
private:
QIcon m_icon;
};
#endif // LINEEDITICON_H
And your source file look like:
#include "lineediticon.h"
#include <QPainter>
LineEditIcon::LineEditIcon(const QIcon icon, QWidget *parent)
: QLineEdit(parent)
{
setIcon(icon);
}
LineEditIcon::~LineEditIcon()
{
}
void LineEditIcon::setIcon(QIcon icon)
{
m_icon = icon;
if (m_icon.isNull())
setTextMargins(1, 1, 1, 1);
else
setTextMargins(20, 1, 1, 1);
}
void LineEditIcon::paintEvent(QPaintEvent * event)
{
QLineEdit::paintEvent(event);
if (!m_icon.isNull()) {
QPainter painter(this);
QPixmap pxm = m_icon.pixmap(height() - 6, height() - 6);
int x = 2, cx = pxm.width();
painter.drawPixmap(x, 3, pxm);
painter.setPen(QColor("lightgrey"));
painter.drawLine(cx + 2, 3, cx + 2, height() - 4);
}
}
Edit: A possible solution is to use a custom plugin to use it directly in QtDesigner.
QT5 addAction
```
const QIcon passwordIcon(":/new/icons/res/passwd.png");
ui->password->setClearButtonEnabled(true);
ui->password->addAction(passwordIcon, QLineEdit::LeadingPosition);
```
From QT 5.2 onwards you can do something like this. You should use pointers if you want to make it more flexible:
QIcon *ico;
ico = new QIcon(":/images/search.ico");
searchEdit->addAction(*ico, QLineEdit::LeadingPosition);

QWidget/QFrame not showing background or border when added to layout

I have a QFrame derived object:
class SubjectLineDisplay : public QFrame
{
Q_OBJECT
private:
// Members
public:
explicit SubjectLineDisplay(const QString&, const QString&, quint32, QWidget *parent = 0);
};
In the constructor, I set a background for it and a border:
QPalette p(palette());
p.setColor(QPalette::Background, QColor(255, 255, 255));
setPalette(p);
setLayout(mainLayout); // The mainLayout is a VBoxLayout which is a collection of a few QLabels
setFixedHeight(lTitle->size().height() + lId->size().height());
When i do this in main():
SubjectLineDisplay* x = new SubjectLineDisplay("NETWORK", "Network Centric Programming", 4);
x->show();
The widget shows up in a window, with the background and frame displaying properly, just as I would want. However, when I add it to another layout to show it:
SubjectLineDisplay* lineDisplay = new SubjectLineDisplay(
subjectNameLE->text(), idLE->text(), creditSpin->value()
);
emit newSubjectAdded(Course(subjectNameLE->text(), idLE->text(), creditSpin->value()));
subjectNameLE->clear();
creditSpin->setValue(3);
idLE->clear();
subjectLineLayout->addWidget(lineDisplay); //Adding the widget to a layout
Now, I don't see the frame or the border. How do I get the layout to display the frame and the border? What am I doing wrong?
Could you try using setAutoFillBackground(true)?
For as far as I'm aware foregrounds are always drawn, but backgrounds are not.

How to display icon in QDockWidget title bar?

My QDockWidget has window title and close button. How do I put icon in title bar?
When I select icon from my recources for QDockWidget WindowIcon property, it's not working either.
Any ideas?
Through custom proxy-style:
class iconned_dock_style: public QProxyStyle{
Q_OBJECT
QIcon icon_;
public:
iconned_dock_style(const QIcon& icon, QStyle* style = 0)
: QProxyStyle(style)
, icon_(icon)
{}
virtual ~iconned_dock_style()
{}
virtual void drawControl(ControlElement element, const QStyleOption* option,
QPainter* painter, const QWidget* widget = 0) const
{
if(element == QStyle::CE_DockWidgetTitle)
{
//width of the icon
int width = pixelMetric(QStyle::PM_ToolBarIconSize);
//margin of title from frame
int margin = baseStyle()->pixelMetric(QStyle::PM_DockWidgetTitleMargin);
QPoint icon_point(margin + option->rect.left(), margin + option->rect.center().y() - width/2);
painter->drawPixmap(icon_point, icon_.pixmap(width, width));
const_cast<QStyleOption*>(option)->rect = option->rect.adjusted(width, 0, 0, 0);
}
baseStyle()->drawControl(element, option, painter, widget);
}
};
example:
QDockWidget* w("my title", paretn);
w->setStyle(new iconned_dock_style( QIcon(":/icons/icons/utilities-terminal.png"), w->style()));
thanks to #Owen, but I'd like add a few notes, for Qt 5.7:
1.QWidget::setStyle() doesn't take owership of the style object, so you need delete it after using it, or it will cause a resource leak.
2.for QProxyStyle(QStyle*), QProxyStyle will take ownership of the input style,
but w->style() may return QApplication's style object if its custom style not set.
so
new iconned_dock_style( QIcon(":/icons/icons/utilities-terminal.png"), w->style())
may take ownership of the app's style object, and on destruction, it will delete it. this will crash the app on QApplicatoin' shutdown time.
so now I use
new iconned_dock_style( QIcon(":/icons/icons/utilities-terminal.png"), NULL)
I think you can use QDockWidget::setTitleBarWidget(QWidget *widget).

Resources