Is it possible to set global QPainter default render hints? - c++

When a QPainter is created, it has some default render hints. Some widgets override them when painting themselves. Is it possible to override these defaults and disable the per-widget overrides for the entire application?
I'd like to override the defaults as follows, and make all widget classes follow these:
painter->setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing, false);
painter->setRenderHints(QPainter::TextAntialiasing , true);
Is it possible?
UPDATE:
Short answer: not possible without changing Qt source code.

Unfortunately, Qt doesn't implement any public way of doing this.
There are two issues:
The default render hint - QPainter::TextAntialiasing is set in QPainter::begin(QPaintDevice*). This is exactly what you wanted according to your question, but
The widgets are free to override these defaults. And many of them do. There is no way to disable that, without inserting a shim paint engine (or similar) that would intercept these and ignore them.
The simplest way to change it is to modify the QPainter::setRenderHint and QPainter::setRenderHints to disable the overrides on certain widget types, and rebuild Qt. In any professional setting you'll be using your own build of Qt anyway, so that shouldn't be an issue.
There probably is a way of hooking it using Qt's private headers, most likely by offering a shim paint engine and swapping it out on the backing store, without modifying Qt itself, but it'll be messy and not worth it.

You can subclass QPainter with:
class MyQPainter: public QWidget
{
Q_OBJECT;
public:
MyQPainter(QWidget *parent = 0);
QPainter painter;
}
and:
MyQPainter::MyQPainter(QWidget *parent)
: QWidget(parent)
{
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing, false);
painter.setRenderHints(QPainter::TextAntialiasing , true);
}
now, you can declare MyQPainter *pPainter = new MyQPainter();

Related

How to add hyperlinks in Qt without QLabel?

I have some labels and layouts nested inside a QWidget to build a part of a sidebar. Each QWidget is its own section and one component currently looks like this:
To my understanding, you can only set hyperlinks with QLabel, but I'm trying to get the whole area between the white lines clickable. This is including the icon and the whitespace. Is there any way to achieve this?
This got marked as a duplicate to the opposite of what I was asking, so I'd like to reiterate that I'm trying to implement a hyperlink without QLabel.
You can easily have a widget open a link on click:
class Link : public QWidget {
Q_OBJECT
public:
Link(QUrl url, QWidget p = nullptr) : QWidget(p), _url(url) {}
QUrl _url;
void mouseReleaseEvent(QMouseEvent *) { QDesktopServices::openUrl(_url); }
}
You can avoid any extra signals and connections, and have each link widget store its own link internally, the url can be set on construction and changed at any time. Not using signals and slots makes it easier to change the link too, without having to disconnect previous connections.
IMO going for a signals and slots solution is only justified when you want different arbitrary behavior. In this case you always want the same - to open a particular link, so you might as well hardcode that and go for an easier and more computationally efficient solution.
I would just manually catch the SIGNAL for clicked() and use desktop services to open the url in code.
bool QDesktopServices::openUrl ( const QUrl & url ) [static]
Opens the given url in the appropriate Web browser for the user's desktop environment, and returns true if successful; otherwise returns false.
http://doc.qt.io/qt-4.8/signalsandslots.html
Using this type of syntax, or in the designer, you can also connect a signal to a slot.
connect(widgetThatRepresentsURL, SIGNAL(clicked()),
handlerThatWillOpenTheURL, SLOT(clicked_on_url()));
For widgets that don't have a signal set up for clicked (or whatever event you are interested in), you can subclass the widget in question and reimplement...
void QWidget::mousePressEvent ( QMouseEvent * event ) [virtual protected]
Specifically for creating a signal, there is emit. I've used this in the past like the following
void Cell::focusInEvent(QFocusEvent *e)
{
emit focus(this, true);
QLineEdit::focusInEvent(e);
}
with the following in the header
signals:
void focus(Cell *, bool);

Set CSS in QPushButton's subclass's constructor

I'm creating my custom push button class by subclassing QPushButton. However for some reason setting that class's CSS in its constructor has no effect; I have to do it in for example paintEvent, then everything is fine. I could just have a global .qss file and set it for the entire application, but I want the class to manage its own styles. Why doesn't my approach work?
The code:
custompushbutton.h
class CustomPushButton: public QPushButton
{
Q_OBJECT
public:
explicit CustomPushButton(QWidget *parent = 0);
~CustomPushButton() = default;
};
custompushbutton.cpp
CustomPushButton::CustomPushButton(QWidget *parent)
: QPushButton(parent)
{
setStyleSheet("background-color: black;"); // this does not work
}
EDIT: For future readers, if you're having a similar issue (i.e. Qt seems to ignore your CSS you set in code), see if you haven't edited the object's styleSheet property in Qt Creator - scroll down in the properties list and make sure styleSheet is empty and NOT BOLD - that was the issue in my case. If it is bold, it means Qt is still using that empty field as the object's CSS, thereby overriding your styles. To clear it either hit the little arrow next to the field in Qt Creator or open up the .ui file and delete the <styleSheet> XML property.
Thanks to JMik for pointing me in the right direction.
The performance cost of setting a stylesheet is surprisingly high, especially if you're developing for an embedded system.
I'd suggest, like you said, using a global stylesheet and specify the class name, like this:
CustomPushButton { background-color: black; }
this way all CustomPushButton will have the same style, and the object will take less time to create.
As for the reason why it doesn't work in your case, I'd guess maybe your accidentally changing the stylesheet again after the creation of the CustomPushButton.
I tested your code on my side and it worked, so it probably has something to do with code your not showing

QMenu item text disappears when icon added

I am attempting to add an icon to my QMenu using Qt Designer, however I realized that my text disappears when my icon is added. Is there any way for me to show my icon next to my text?
It was not supported in Qt 4, maybe it is in Qt5 I haven't checked.
In Designer itself there isn't much you can do. In the code one option is to customize the style to draw both the icon and text:
- sizeFromContents for QStyle::CT_MenuBarItem
- drawControl for QStyle::CE_MenuBarItem
- drawCustomControl for QStyleOptionMenuItem
This is not supported by default, mostly because it is not usual an operation that you wish to achieve in here. Of course, you could always use an image with text included, but that is also hackish, unless you paint the image dynamically and then load it later. Although even that would be quite a bit of work.
In order to do, you will need to fiddle with Qt a bit. This is the closest experiment that I would start off with, personally. I have not had time to check whether it actually works, but there should be something among these lines:
class CustomMenuBarWidget : public QWidget
{
public:
explicit CustomMenuBarWidget(QWidget *parent = Q_NULLPTR)
: QWidget(parent)
, menuBar(new QMenuBar())
{
}
virtual void paintEvent(QPaintEvent *event) {
QStyleOptionMenuItem styleOptionMenuItem;
QIcon icon("path/to/my/icon");
styleOptionMenuItem.icon = icon;
styleOptionMenuItem.text = "Hello World!";
QPainter painter(this);
menuBar->style()->drawControl(QStyle::CE_MenuBarItem, &styleOptionMenuItem, &painter, menuBar);
}
private:
QMenuBar *menuBar;
};
You could probably also have a look at QWidgetAction how to insert custom widgets into toolbars and menubars. I have never used that myself in any serious project, but might be useful to be aware of.

Why do we pass "this" pointer to setupUi function?

I'm fairly new in QT. Taking below fairly simply explain from qt docs :
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
private:
Ui::CalculatorForm ui;
};
and implementation of constructor
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this); // <-- Question below
}
Q: I was wondering why do we pass this pointer to setupUi function?, what does it do ?
So that the dialog will have the caller as parent, so that eg when the parent is closed the dialog can be closed automatically. Generally all gui elements have a pointer to their parent.
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
These are auto generated slots which exactly match the naming of the gui elments in QtDesigner. They are only meant to do the direct hookup to those gui elements and so should be dealt with in this class. If these signals were extended to other classes then any change in the gui would require changing a lot of other code which doesn't need to know details of the gui.
In the handler slot for the specific gui element you can then emit another more general signal to the rest of the app.
The only widget that setupUi doesn't create is the widget at the top of the hierarchy in the ui file, and as the Ui::CalculatorForm class instance doesn't know the widget it has to fill, it (this) has to be passed explicitly to the class at some point.
this or any other widget you would pass to it, is used as the parent to all other subwidgets. For example, you could fill a widget without inheritance like this:
QWidget *widget = new QWidget;
Ui::CalculatorForm *ui = new Ui::CalculatorForm;
ui->setupUi(widget);
widget->show();
But really, it would be easier to understand if you read the content of the uic generated file (probably named ui_calculatorform.h).
setupUi creates the instances of widgets (QLabel, QTextEdit and so on). The [user interface compiler] (http://qt-project.org/doc/qt-4.8/uic.html) gets information for you from the .UI form and generates widget-creation code in the generated moc source files.
The manual way of creating widgets without using the Qt Designer or a UI file would be like so:
QWidget* pWidget = new QWidget(this);
I think it is to add the caller widget to the layout of this UI.
This widget will be the toplevel widget.
Martin Beckett answer might be correct as well, as what he described is a common behavior in Qt (cf the 'parent' argument in most of widget's derived class constructor)
Note that you have alternative ways how designer can auto-generate code.
In this case you have a separate 'UI' class for this code which is not QObject so it also is not a QWidget.
Auto generated code needs information about parent widget and to make auto-conections of slots and signals so this is why you have to pass this.
This pater is less intrusive then other pasterns (that is why it is default). You can also try alternative patters (check Qt Creator Designer options), but I recommend you to see what is generated by designer tools in default settings.

qt GUI connecting

I am just starting out with QT. I have read through some tutorials, and I think I have an understanding of signals and slots. I am writing a GUI that has various buttons that change the state of my main program. So for example in a drawing app, you would pick different drawing tools (using various buttons).
What is the best way to go about this? My first thought was to try to connect the clicked signal of the PushButton to some function that sets a current_tool variable. I did some searching and couldn't find a way to connect a QObject signal to a regular function.
This leads me to believe that there is probably a different approach. One where I create a new QObject (my own extension that is) that has various GUI properties. I would then define my slots here for the various buttons.
What is the best way to do this in QT. I am new and do not know of the preferred practice.
Any info would be useful,
thanks
You can define these "normal functions" as slots. Slots are just normal functions that can also be called by signals:
class ToolSelector : public QObject {
Q_OBJECT
public:
Tool *selected;
public slots:
void selectBrush();
void selectPen();
void selectFill();
};
ToolSelector::selectBrush() {
delete selected;
selected = new Brush();
}
ToolSelector::selectPen() {
// ...
}
// ...
toolsel = new ToolSelector();
brushButton = new QPushButton();
connect(brushButton, SIGNAL(clicked()), toolsel, SLOT(selectBrush()));
Inherit from the class that uic generates, creating, say, a MyAppWindow class. Provide extra METHODs in that class, as well as a Document or Drawing object. Connect these methods to the signals you're interested in, and them alter a member variable that contains the drawing state.