QPushButton#PBack {
background: #9A9AFF;
font: bold 28pt "Brutal Type";
color: #000000;
border: 3px solid #000000;
border-radius: 25px;
}
QPushButton#PBack:disabled {
background-color: #bdbdbd;
border-color: #787878;
}
How to get border-color inside of paintEvent?
void W_PBackButton::paintEvent(QPaintEvent* event)
{
// Here i use constants
if (isEnabled() == true)
painter.setPen(QPen(QBrush(_enabled), 3));
else
painter.setPen(QPen(QBrush(_disabled), 3));
painter.fillPath(path, palette().base());
painter.drawPath(path);
}
In example i use constants, but how to get color values from palette or styles?
Need to draw triangle button
Now, given the fact question is filled in with more information, I think I can provide some answer. Well, I do not think you need to try getting some "border" property which is declared by Qt. It would be much more difficult. Instead, you can define your own custom property, e.g. "borderColor" (or a couple of them, such for thickness, shape, and so on), and set it like this through stylesheet: "qproperty-borderColor". About definition of custom properties, you can read more information here: https://doc.qt.io/qt-5/properties.html (and an example would be https://doc.qt.io/qt-5/properties.html#a-simple-example ).
The following code illustrates possible way of setting property desired. First of all, you would have to define your own class inheriting the class on which you want property to be set. Let's say it is child of QPushButton:
#include <QPushButton>
class CustomButton
: public QPushButton
{
Q_OBJECT
Q_PROPERTY(QColor borderColor READ GetBorderColor WRITE SetBorderColor)
public:
CustomButton(QWidget *parent = nullptr);
virtual ~CustomButton();
QColor GetBorderColor() const;
void SetBorderColor(const QColor& color);
protected:
virtual void paintEvent(QPaintEvent* event) override;
private:
QColor m_borderColor;
};
#include "CustomButton.h"
#include <QDebug>
CustomButton::CustomButton(QWidget *parent)
: QPushButton(parent)
{
}
CustomButton::~CustomButton()
{
}
QColor CustomButton::GetBorderColor() const
{
return m_borderColor;
}
void CustomButton::SetBorderColor(const QColor& color)
{
m_borderColor = color;
qDebug() << m_borderColor;
}
void CustomButton::paintEvent(QPaintEvent* event)
{
QPushButton::paintEvent(event);
// Do whatever you like with m_borderColor and any other properties.
}
And finally, you would have to promote you QPushButton in the Qt Creator to your own CustomButton. Regarding widgets promotion, you can read about it here: https://doc.qt.io/archives/qt-4.8/designer-using-custom-widgets.html#promoting-widgets
And when you have everything setup, you can easily declare stylesheet for your newly introduced button:
#pushButton {
qproperty-borderColor: #123456;
}
Maybe it is not the way you have intented to achieve your goal initially, but it looks like that declaring custom stylesheet properties and using promotion of widgets would help you achieve your goal without any hacking and in a way Qt was been built to be used. Hopefully, it helps you. :)
Related
I need to make an element like this:
It's a combination of a line edit and a button with the same height and no space between them.
I have tried in Qt Designer but the height of them is not the same and there is always a small space between these 2 elements.
How can I solve this problem?
Maybe you could customize a QComboBox, something like this:
#include <QComboBox>
#include <QLineEdit>
class CustomBox : public QComboBox
{
Q_OBJECT
public:
CustomBox(QWidget * parent = nullptr) : QComboBox(parent)
{
setEditable(true);
QString ss =
"QComboBox::drop-down {border: none;}"
"QComboBox::down-arrow { image: url(/data/whatever.png); }"
"QComboBox::down-arrow:pressed { image: url(/data/whatever-pressed.png); }";
setStyleSheet(ss);
connect(lineEdit(), &QLineEdit::editingFinished, [this](){
QString t = lineEdit()->text();
clear();
lineEdit()->setText(t);
});
}
void setText(const QString & t) { lineEdit()->setText(t); }
QString text() const { return lineEdit()->text(); }
protected:
void showPopup() override
{
emit buttonClicked();
}
signals:
void buttonClicked();
};
The combo box is set as editable, so you can use an underlying QLineEdit, which is, more or less, under full control through the protected lineEdit member function. As you can see, I connected its editingFinished signal to a lambda to avoid adding items to the combo each time (this happens when the user press Enter in an editable combo box).
The styling is quite simple, given that you have a couple of icons for the button.
I exposed the line edit text getter/setter, and added a signal for the button click, which gets emitted from the showPopup protected method (called when the user press the button).
Just an idea.
I'm trying to use QSS to customize the look of the tool-tip, it works. However, if I try showing the tooltip using QToolTip::showText function, it won't work as intended which means that the QToolTip style sheet doesn't apply to it probably?
My purpose: When changing a slider value I want to show a rectangle somewhere near the slider, so I thought the tooltip was the easiest way to do it?
If you don't understand what I mean, I'm trying to make sliders in Qt feel like Windows 10 UWP so if you want to understand what I mean look for example any slider in Windows like go to Settings->System->Sound and see how their slider works. I've done everything they have except that rectangle which shows when value get changed.
What I'm trying to do:
In the style sheet
QToolTip
{
color: red;
}
In my custom Slider class (inherited from QSlider)
class FSlider : public QSlider
{
Q_OBJECT
public:
FSlider(QWidget *parent = 0) : QSlider(parent) { connect(this, SIGNAL(valueChanged(int)), this, SLOT(notifyValueChanged(int))); }
protected:
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
bool event(QEvent* event);
private slots:
void notifyValueChanged(int Value);
};
void FSlider::notifyValueChanged(int Value)
{
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect sliderHandle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle);
QToolTip::setFont(QFont("Segoe UI", 13, 400));
QToolTip::showText(mapToGlobal(QPoint(sliderHandle.x() - sliderHandle.width() - 2, sliderHandle.y() - sliderHandle.height() - 30)), QString::asprintf("%i", Value));
}
Thanks for reading !
I had the same issue at first with Qt 5.12.2. I was missing the third argument to QToolTip::showText. I had to add the parent widget. In that case, the CSS that I had applied to the tooltip in mainwindow.ui applied to the QToolTip . Without the parent, it is a separate window shown on the position specified and has no knowledge of the css.
I've currently got this style for all push buttons:
this->setStyleSheet(".QPushButton { background-color: #416eb6; color: #ddd; }");
This is great because it allows me to keep a constant styling for all the QPushButton's without having to style them individually.
An issue arises when I need to style a QPushButton representing a color chooser. The button should represent the color that was chosen from the color chooser, but instead it just keeps the initial style that I set.
Things I have tried:
Giving an empty style sheet for the item:
this->setStyleSheet(#m_colorChooserButton { });
Setting the style to initial:
this->setStyleSheet(#m_colorChooserButton { background-color: initial});
Using a similar css selector :not:
this->setStyleSheet(".QPushButton:not(#m_colorChooserButton) { background-color: #416eb6; color: #ddd; }");
Is there any way to achieve this result?
I'd like to mimic the :not selector if possible since that's the most straightforward, but at this point, I'd do anything that works.
I'd like to avoid having to manually specify the style for each button I want it to show on, as there are well over 100 buttons and finding the object names of these buttons is very time consuming (large legacy code base).
Thanks
You have 2 choices: apply a stylesheet to just that button and invalidate/reapply it every time you change the selected colour or just subclass that button and reimplement the paintevent:
class ColorButton : public QPushButton{
Q_OBJECT
Q_DISABLE_COPY(ColorButton)
public:
ColorButton(QWidget* parent = Q_NULLPTR)
:QPushButton(parent)
,m_color(Qt::red)
{}
const QColor& color() const {return m_color;}
void setColor(const QColor& val){if(m_color==val) return; m_color=val; update();}
protected:
void paintEvent(QPaintEvent *)
{
QStylePainter p(this);
QStyleOptionButton option;
initStyleOption(&option);
option.palette.setColor(m_color,QPalette::Background);
p.drawControl(QStyle::CE_PushButton, option);
}
private:
QColor m_color;
};
P.S.
The KDE API already has that widget: https://api.kde.org/frameworks-api/frameworks-apidocs/frameworks/kwidgetsaddons/html/classKColorButton.html
I have a QLabel, and I want the text inside of it to appear engraved, similar to the text-shadow approach in CSS. Is there a way to do this in Qt?
Much more easier than overriding the paintEvent is using a QGraphicsEffect, precisely QGraphicsDropShadowEffect.
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
effect->setBlurRadius(5);
effect->setXOffset(5);
effect->setYOffset(5);
label->setGraphicsEffect(effect);
and the result is something like this:
If you want to color the shadow you can easily achieve this through QGraphicsDropShadowEffect::setColor member function.
Hope this helps.
This can be accomplished by overriding the label's paint event in a subclass. Example:
#include <QRect>
#include <QLabel>
#include <QPainter>
class QEngravedLabel : public QLabel
{
public:
explicit QEngravedLabel(QWidget *parent=0, Qt::WindowFlags f=0)
: QLabel(parent, f){};
explicit QEngravedLabel(const QString &text, QWidget *parent=0, Qt::WindowFlags f=0)
: QLabel(text,parent,f){};
protected:
virtual void paintEvent(QPaintEvent *pe) override
{
QRect toPaint(pe->rect());
QPainter painter(this);
toPaint.translate(0,1);
painter.setPen(QColor("#CCC")); // light shadow on bottom
painter.drawText(toPaint, this->alignment() ,this->text());
toPaint.translate(0,-2);
painter.setPen(QColor("#333")); // dark shadow on top
painter.drawText(toPaint, this->alignment() ,this->text());
toPaint.translate(0,1);
painter.setPen(QColor("#000000")); // text
painter.drawText(toPaint, this->alignment() ,this->text());
}
};
These shadow colors are tailored for a light gray background.
I've created a custom QLineEdit widget that handles drag and drop of files. Everything is working great with that part, but as soon as I add a Class variable the application crashes either at the construction of the class or at destruction:
When my variable is QString, it crashes at construction
When my variable is QString*, it crashed at destruction
I tried deleting the variable (QString*) in the destructor, same issue...
Any ideas?
Header:
#ifndef DROPLINEEDIT_H
#define DROPLINEEDIT_H
#include <QLineEdit>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QString>
#include <QDebug>
class DropLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit DropLineEdit(QWidget *parent = 0);
~DropLineEdit();
protected:
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event);
virtual void dragLeaveEvent(QDragLeaveEvent *event);
signals:
public slots:
private:
QString * mFileName;
};
#endif // DROPLINEEDIT_H
Source:
#include "droplineedit.h"
DropLineEdit::DropLineEdit(QWidget *parent) :
QLineEdit(parent)
{
setAcceptDrops(true);
this->setReadOnly(true);
this->setStyleSheet("QLineEdit { border: 2px solid gray ; border-radius: 8px ; padding: 0 6px }");
}
DropLineEdit::~DropLineEdit()
{
if(!mFileName){
delete mFileName;
}
}
// **************************************** PROTECTED METHODS **************************************** //
void DropLineEdit::dragEnterEvent(QDragEnterEvent *event){
this->setStyleSheet("QLineEdit { border: 3px solid black ; border-radius: 8px ; padding: 0 6px }");
event->accept();
}
void DropLineEdit::dragLeaveEvent(QDragLeaveEvent *event){
this->setStyleSheet("QLineEdit { border: 2px solid gray ; border-radius: 8px ; padding: 0 6px }");
event->accept();
}
void DropLineEdit::dropEvent(QDropEvent *event){
// Get the data. If multiple files are dropped, take only the first one and fetch save its info
QList<QUrl> list = event->mimeData()->urls();
QFileInfo * fileInfo = new QFileInfo(list.at(0).toLocalFile());
qDebug() << fileInfo->absoluteFilePath();
mFileName = new QString(fileInfo->absoluteFilePath());
this->setText(fileInfo->fileName());
this->setStyleSheet("QLineEdit { border: 2px solid gray ; border-radius: 8px ; padding: 0 6px }");
event->accept();
}
Add this to the constructor:
mFileName = 0;
You need to initialize the pointer. Otherwise it will have random value and you will be unable to check if you have created an object.
Modify the destructor:
delete mFileName;
You need to delete object if it's not NULL (your version is the opposite). delete will perform the check internally.
Note that if mFileName = new QString... is executed multiple times, several objects will be created. You need to delete previous object before creating new one if you need to avoid memory leak.
However, all the above information is provided for general education. You should not use QString* here. Non-pointer QString class member will be much more correct. In this case you don't need to use new or delete, you don't need to care about pointers and memory at all.
I was getting this as an error in debug: "invalid address specified to rtlfreeheap"
I did some research on that and found out that it could be related to an internal issue with Qt (the way object constructors are called). I went back in my main application to see how I called my DropLineEdit object and notice that I forgot to remove the setAcceptDrops(true) after creating DropLineEdit Classe (the object was formerly a normal QLineEdit before I created DropLineEdit).
Here was the function call:
DropLineEdit* Instrument::createDropLineEdit(){
DropLineEdit * lineEdit = new DropLineEdit();
lineEdit->setAcceptDrops(true);
return lineEdit;
}
Changed to:
DropLineEdit* Instrument::createDropLineEdit(){
DropLineEdit * lineEdit = new DropLineEdit();
return lineEdit;
}
After removing that redundant call (redundant since the acceptdrops was set in the constructor), I didn't get any application crash either with QString or QString* as member variable of DropLineEdit Class. I used a QString (not the pointer) and I was able to make my Class do what is was supposed to.
Thanks for your replies guys. Much appreciated.