Increase button font size when button size is changing - qt

I'm having a Qt application with a main window that has five buttons aligned in a vertical order.
They all have the same size.
All I want to do is to increase the font size of the button label when the app goes fullscreen.
I would really appreciate a solution that does not need too much code ... was hoping that this was something that could be done in Qt Designer, but I couldn't find a way how to.
Any suggestions?
Best,
guitarflow

I can't think of any way to do it in designer, but it's really not too much code. Here's a quick-and-dirty proof of concept. You'd want to take into account margins (using QStyle::pixelMetrics and the like), but you get the idea.
#include <QtGui>
class FontAdjustingButton : public QPushButton {
public:
explicit FontAdjustingButton(QWidget *parent = NULL) : QPushButton(parent) {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
protected:
void resizeEvent(QResizeEvent *event) {
int button_margin = style()->pixelMetric(QStyle::PM_ButtonMargin);
QFont f = font();
f.setPixelSize(event->size().height() - button_margin * 2);
setFont(f);
}
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
QWidget w;
QVBoxLayout *layout = new QVBoxLayout;
for (int i = 0; i < 5; ++i) {
FontAdjustingButton *btn = new FontAdjustingButton;
btn->setText(QString("Hello, world %1").arg(i));
layout->addWidget(btn);
}
w.setLayout(layout);
w.show();
return app.exec();
}

Related

How to include in a main QLabel a subset of widgets (e.g. QListView and QLabels)

In order to test a rotation of a QImage I created a quick application where I subclassed a QLabel as shown below. Basically the QLabel acts as MainWindow for me in this case.
Below is the lay-out I have:
Below is the lay-out I am trying to achieve:
Below the code
mainwindow.h
class MainWindow : public QLabel {
Q_OBJECT
public:
MainWindow(int argc, char** argv, QWidget *parent = {});
virtual ~MainWindow();
protected:
Q_SLOT void setImageMsg(const sensor_msgs::ImageConstPtr&);
Q_SIGNAL void newImageMsg(const sensor_msgs::ImageConstPtr&);
private:
ros::Subscriber sub;
ros::Subscriber sub_img_bw;
};
mainwindow.cpp
MainWindow::MainWindow(int argc, char** argv, QWidget *parent) : QLabel(parent) {
qRegisterMetaType<sensor_msgs::ImageConstPtr>();
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
connect(this, &MainWindow::newImageMsg, this, &MainWindow::setImageMsg);
#else
connect(this, SIGNAL(newImageMsg(sensor_msgs::ImageConstPtr)), SLOT(setImageMsg(sensor_msgs::ImageConstPtr)));
#endif
ros::init(argc,argv,"MainWindow");
ros::NodeHandle n;
QComboBox *comboColorBckgd = new QComboBox(this);
QStringList sequence_len = QStringList() << tr("Bckgd Color") << tr("Green") << tr("Blue") << tr("Black");
comboColorBckgd->addItems(sequence_len);
QComboBox *comboColorBeam = new QComboBox(this);
QStringList sequence_len_beam = QStringList() << tr("Beam Color") << tr("R") << tr("G") << tr("B");
comboColorBeam->addItems(sequence_len_beam);
QGridLayout *grid = new QGridLayout(this);
grid->setColumnMinimumWidth(0, 10);
grid->addWidget(comboColorBckgd, 0, 0, Qt::AlignTop);
grid->addWidget(comboColorBeam, 0, 1, Qt::AlignTop);
comboColorBckgd->show();
comboColorBeam->show();
}
I am facing here the situation where I don't exactly understand why I can't divide the main QLabel in subsessions where :
one row has one QLabel and one QListView and
another row has 'QListViewandQLabel`
As shown in the layout I am trying to achieve.
Of course I tries to insert the necessary components in the function
`MainWindow::MainWindow(int argc, char** argv, QWidget *parent) : QLabel(parent) {
// .. desired componentns here
}
Despite I am able to add all the components my final layout is extremely disordered and everything falls under the single QLabel despite I am sure I set the QGridLayout correctly.
Maybe do I have to subclass a QGridLayout? I am confused.
I am not sure how to move on and I would like to thank anyone in advance for shedding light on what is happening or at lest pointing to a potential solution.
I'm not able to see your images for the layout you have and are trying to achieve so I may not totally understand your problem but...
Why do you have to subclass QLabel? I imagine that is causing your problems - QLabel is not expecting to have a child hierarchy underneath it and so it is probably conflicting with QLabel.
Instead of this parent/child hierarchy:
- MainWindow : public QLabel
-- QGridLayout
--- QComboBox
--- QComboBox
Have you tried:
- MainWindow : public QWidget (or QMainWindow?)
-- QGridLayout
--- QLabel (top level)
--- QComboBox
--- QComboBox

Qt: How to link hand coded UI with UI builder?

I am looking for an easy way to link hand coded design to the UI for widgets applications in Qt. I plan to use the UI builder to easily adjust the layouts and obtain proper spacing, which I find hard to do without the UI builder.
I want to create a 3x3 grid of buttons for which I plan to use QVector< QVector<QPushButton*> > (I am not sure how I would do this in UI builder.)
Here is what I have tried, Why are the buttons not displayed even when I set the parent of each button to the widget ?
main.cpp
#include "window.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QPushButton>
namespace Ui {
class Window;
}
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
~Window();
private:
Ui::Window *ui;
static const int tiles = 50, height = 600, width = 500;
QVector< QVector<QPushButton*> > cells;
};
#endif // WINDOW_H
window.cpp
#include "window.h"
#include "ui_window.h"
Window::Window(QWidget *parent) :
QWidget(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
this->resize(width, height);
int j = 0;
for(auto &row : cells)
{
int i = 0;
for(auto &col : row)
{
col = new QPushButton(this);
col->setGeometry(i, j, tiles, tiles);
i += tiles;
}
j += tiles;
}
}
Window::~Window()
{
delete ui;
for(auto &row : cells)
{
for(auto &col : row)
{
delete col;
}
}
}
Any help would be appreciated.
The vectors are empty, so you iterate over nothing. Instead of managing these manually, you could leverage the grid layout.
Alas, you're complicating things unnecessarily with all the manual memory management and geometry management. It's unnecessary. All you need to do is to add widgets to the layout you allude to. And even then, I don't see how relegating the layout to a .ui file helps you since there the layout must be empty. So yes: you can set spacings, but you won't see them until you run the code. So it seems like a pointless exercise, unless you have other elements you're not telling us about (why aren't you - you went so far already).
Below is a minimum example that simplifies it as much as practicable, but see this answer and the links therein for more idea.
// https://github.com/KubaO/stackoverflown/tree/master/questions/button-grid-43214317
#include <QtWidgets>
namespace Ui { class Window {
public:
// Approximate uic output
QGridLayout *layout;
void setupUi(QWidget * widget) {
layout = new QGridLayout(widget);
}
}; }
class Window : public QWidget
{
Q_OBJECT
Ui::Window ui;
QPushButton * buttonAt(int row, int column) {
auto item = ui.layout->itemAtPosition(row, column);
return item ? qobject_cast<QPushButton*>(item->widget()) : nullptr;
}
public:
explicit Window(QWidget *parent = {});
};
Window::Window(QWidget *parent) : QWidget(parent) {
ui.setupUi(this);
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 6; ++j)
{
auto b = new QPushButton(QStringLiteral("%1,%2").arg(i).arg(j));
ui.layout->addWidget(b, i, j);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"

Qt: How to draw a dummy line edit control

I have a QPainter, and a rectangle.
i'd like to draw a QLineEdit control, empty. Just to draw it, not to have a live control. How do I do that? I have tried QStyle::drawPrimitive to no avail. nothing gets drawn.
QStyleOption option1;
option1.init(contactsView); // contactView is the parent QListView
option1.rect = option.rect; // option.rect is the rectangle to be drawn on.
contactsView->style()->drawPrimitive(QStyle::PE_FrameLineEdit, &option1, painter, contactsView);
Naturally, i'd like the drawn dummy to look native in Windows and OSX.
Your code is pretty close, but you would have to initialize the style from a fake QLineEdit. The following is based on QLineEdit::paintEvent and QLineEdit::initStyleOption.
#include <QtGui>
class FakeLineEditWidget : public QWidget {
public:
explicit FakeLineEditWidget(QWidget *parent = NULL) : QWidget(parent) {}
protected:
void paintEvent(QPaintEvent *) {
QPainter painter(this);
QLineEdit dummy;
QStyleOptionFrameV2 panel;
panel.initFrom(&dummy);
panel.rect = QRect(10, 10, 100, 30); // QFontMetric could provide height.
panel.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth,
&panel,
&dummy);
panel.midLineWidth = 0;
panel.state |= QStyle::State_Sunken;
panel.features = QStyleOptionFrameV2::None;
style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &painter, this);
}
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
FakeLineEditWidget w;
w.setFixedSize(300, 100);
w.show();
return app.exec();
}

How to add a tick mark to a slider if it cannot inherit QSlider

I have a Qt dialog and there is a slider in it, when the dialog is initialized the slider will be set a value. In order to remind the user what is the default value, I want to add a mark to the slider, just draw a line or a triangle above the handle. Here, the slider should be of QSlider type, that means I can't implement a customized control derived from QSlider. Is there any way to realize it ?
I'm not clear why you can't derive a control from QSlider. You can still treat it like a QSlider, just override the paintEvent method. The example below is pretty cheesy, visually speaking, but you could use the methods from QStyle to make it look more natural:
#include <QtGui>
class DefaultValueSlider : public QSlider {
Q_OBJECT
public:
DefaultValueSlider(Qt::Orientation orientation, QWidget *parent = NULL)
: QSlider(orientation, parent),
default_value_(-1) {
connect(this, SIGNAL(valueChanged(int)), SLOT(VerifyDefaultValue(int)));
}
protected:
void paintEvent(QPaintEvent *ev) {
int position = QStyle::sliderPositionFromValue(minimum(),
maximum(),
default_value_,
width());
QPainter painter(this);
painter.drawLine(position, 0, position, height());
QSlider::paintEvent(ev);
}
private slots:
void VerifyDefaultValue(int value){
if (default_value_ == -1) {
default_value_ = value;
update();
}
}
private:
int default_value_;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
DefaultValueSlider *slider = new DefaultValueSlider(Qt::Horizontal);
slider->setValue(30);
QWidget *w = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(slider);
layout->addStretch(1);
w->setLayout(layout);
QMainWindow window;
window.setCentralWidget(w);
window.show();
return app.exec();
}
#include "main.moc"
Easiest way I can think off is:
Add QSlider to QSlider (like you do it with layouts and QFrames). Slider above will be your current slider (clickable one). Slider below will be your "default tick position" value.
#include <QApplication>
#include <QSlider>
#include <QVBoxLayout>
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
QSlider * defaultValueSlider = new QSlider();
QSlider * valueSlider = new QSlider(defaultValueSlider);
QVBoxLayout * lay = new QVBoxLayout(defaultValueSlider);
lay->setContentsMargins(0, 0, 0, 0);
lay->setSpacing(0);
lay->addWidget(valueSlider);
defaultValueSlider->setRange(0, 100);
valueSlider->setRange(0, 100);
defaultValueSlider->setValue(30);
defaultValueSlider->show();
return app.exec();
}
Why do you need to inherit a QSlider to access its public methods?
http://doc.trolltech.com/4.7/qslider.html
You can just call its setTickPosition() in your app.

How to make a QWidget alpha-transparent

I need to create an alpha transparent widget, it's basically a navigation bar with a shadow and the widgets below need to be partially visible through the shadow. The widget loads a PNG then draws it on the paint event. The problem is that the shadow is all black and is not alpha-transparent.
This is the code I'm currently using:
NavigationBar::NavigationBar(QWidget *parent) : XQWidget(parent) {
backgroundPixmap_ = new QPixmap();
backgroundPixmap_->load(FilePaths::skinFile("NavigationBarBackground.png"), "png");
setAttribute(Qt::WA_NoBackground, true); // This is supposed to remove the background but there's still a (black) background
}
void NavigationBar::paintEvent(QPaintEvent* event) {
QWidget::paintEvent(event);
QPainter painter(this);
int x = 0;
while (x < width()) {
painter.drawPixmap(x, 0, backgroundPixmap_->width(), backgroundPixmap_->height(), *backgroundPixmap_);
x += backgroundPixmap_->width();
}
}
Does anybody know what I need to change to make sure the widget is really transparent?
You're doing too much work :-)
The setAttribute call is not necessary. By default, a widget will not draw anything on its background (assuming Qt >= 4.1). Calling QWidget::paintEvent is also unnecessary - you don't want it to do anything.
Rather than doing the pattern fill yourself, let Qt do it with a QBrush:
NavigationBar::NavigationBar(QWidget *parent) : XQWidget(parent) {
backgroundPixmap_ = new QPixmap();
backgroundPixmap_->load(FilePaths::skinFile("NavigationBarBackground.png"), "png");
// debug check here:
if (!backgroundPixmap_->hasAlphaChannel()) {
// won't work
}
}
void NavigationBar::paintEvent(QPaintEvent* event) {
QPainter painter(this);
painter.fillRect(0, 0, width(), height(), QBrush(*backgroundPixmap));
}
Adjust the height parameter if you don't want the pattern to repeat vertically.
Are you sure your PNG file is actually transparent? The following (which is essentially what you are doing) is working for me. If this fails on your machine, perhaps include what version of Qt you are using, and what platform.
#include <QtGui>
class TransparentWidget : public QWidget {
public:
TransparentWidget()
: QWidget(),
background_pixmap_(":/semi_transparent.png") {
setFixedSize(400, 100);
}
protected:
void paintEvent(QPaintEvent *) {
QPainter painter(this);
int x = 0;
while (x < width()) {
painter.drawPixmap(x, 0, background_pixmap_);
x += background_pixmap_.width();
}
}
private:
QPixmap background_pixmap_;
};
class ParentWidget : public QWidget {
public:
ParentWidget() : QWidget() {
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new TransparentWidget);
layout->addWidget(new QPushButton("Button"));
setLayout(layout);
setBackgroundRole(QPalette::Dark);
setAutoFillBackground(true);
}
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
ParentWidget w;
w.show();
return app.exec();
}

Resources