QTableWidget: Row does not size properly - qt

I am implementing a small example using a QTableWidget with specific headers.
However, as soon as I run the example the rows do not stretch properly as it is possible to see in the following example (which is the wrong behavior):
After manual resizing I obtain what I am looking for (which is the expected behavior):
prescriptiondialog.h
class PrescriptionDialog : public QDialog
{
Q_OBJECT
public:
PrescriptionDialog();
~PrescriptionDialog();
QPushButton *mAddButton;
QPushButton *mRemoveButton;
QLineEdit *durationEdit;
QLabel *durationLbl;
DrugTable *mTable;
};
#endif // PRESCRIPTIONDIALOG_H
prescriptiondialog.cpp
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QHeaderView>
PrescriptionDialog::PrescriptionDialog()
{
setWindowTitle("Drug Mixer");
mTable = new DrugTable();
mTable->horizontalHeader()->setStretchLastSection(4);
mTable->verticalHeader()->setStretchLastSection(QHeaderView::Interactive);
mTable->show();
QObject::connect(mAddButton, &QPushButton::clicked, mTable, &DrugTable::addCustomRow);
QObject::connect(mRemoveButton, &QPushButton::clicked, mTable, &DrugTable::removeCustomRow);
setLayout(mLay);
show();
}
What I have done so far:
1) I tried to use the headers in the following way, but that did not give the expected behavior.
The problem with this approach is that columns are equally spaced (I am not looking for this specific behavior because I need the user to adjust them as they want) and, most importantly, the row takes the whole space of the application window making the row extremely big.
PrescriptionDialog::PrescriptionDialog()
{
setWindowTitle("Drug Mixer");
mTable = new DrugTable();
mTable->horizontalHeader()->setStretchLastSection(4);
mTable->verticalHeader()->setStretchLastSection(QHeaderView::Interactive);
QHeaderView* header = mTable->horizontalHeader();
header->setSectionResizeMode(QHeaderView::Stretch);
QHeaderView* headerRows = mTable->verticalHeader();
headerRows->setSectionResizeMode(QHeaderView::Stretch);
mTable->show();
}
2) I tried the option of using the horizontalHeader() provided by the QTableWidget but that didn't provide any improvements and actually I obtained the effect of the first screenshot (the "When To Take" column is all compressed until I manually adjust )
PrescriptionDialog::PrescriptionDialog()
{
setWindowTitle("Drug Mixer");
mTable = new DrugTable();
mTable->horizontalHeader()->setStretchLastSection(4);
mTable->verticalHeader()->setStretchLastSection(QHeaderView::Interactive);
mTable->resizeRowsToContents();
mTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);
mTable->show();
}
3) I came across this source, this other source but none of them provided light on how to solve the issue.
4) I dug more into the problem and went through this which is using the property of resizeRowsToContents() which I used in the example but didn't change anything in the final result.
Thanks for shedding light ob this and provide guidance on how to solve the problem.

I tried to make a small example using resizeRowsToContents() and it works well for me.
Tested on Qt 5.15.1 MinGW.
#include "mainwindow.h"
#include <QTableView>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QStandardItemModel>
#include <QHeaderView>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QStandardItemModel *model = new QStandardItemModel{this};
model->appendRow({new QStandardItem{tr("Drug")}, new QStandardItem{}});
QTableView *view = new QTableView{this};
view->setModel(model);
QHBoxLayout *horz_layout = new QHBoxLayout;
horz_layout->addWidget(new QPushButton{tr("Add when"), this});
horz_layout->addWidget(new QPushButton{tr("Remove when"), this});
QStandardItemModel *inner_model = new QStandardItemModel{this};
inner_model->setHorizontalHeaderLabels({tr("Select"), tr("When to take")});
QTableView *inner_view = new QTableView{this};
inner_view->setModel(inner_model);
QWidget *widget = new QWidget;
QVBoxLayout *vert_layout = new QVBoxLayout{widget};
vert_layout->addLayout(horz_layout);
vert_layout->addWidget(inner_view);
view->horizontalHeader()->setStretchLastSection(true);
view->setIndexWidget(model->index(0, 1), widget);
view->resizeRowToContents(0);
this->setCentralWidget(view);
this->resize(500, 500);
}
MainWindow::~MainWindow()
{
}
Result:

Related

Not mirroring layout direction in some of Qt widgets

I have an application which should have a right-to-left layout direction. But there some widgets(e.g. a QComboBox and a QlistWidget) which i don't want to mirror layout-direction (they should have left-to-right layout-direction whatever the layout-direction of app is).
What I'm looking for is something like LayoutMirroring.enabled in qml.
Is there a solution for this?
Edit:
This is a very simplified version of my code:
file widget.h:
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
file widget.cpp:
Widget::Widget(QWidget *parent): QWidget(parent){
setMinimumSize(300, 300);
QLabel *label1 = new QLabel("Right to left 1");
QLabel *label2 = new QLabel("Right to left 2");
QLabel *label3 = new QLabel("Right to left 3");
QComboBox *mCombo = new QComboBox();
mCombo->setMinimumWidth(150);
mCombo->addItems(QStringList({"Left to Right 1", "Left to Right 2", "Left to Right 3"}));
mCombo->setStyleSheet("QComboBox{padding: 0 10 0 10;}");
mCombo->setLayoutDirection(Qt::LeftToRight);
QVBoxLayout *mainlayout = new QVBoxLayout();
mainlayout->setAlignment(Qt::AlignLeft);
mainlayout->addWidget(mCombo);
mainlayout->addWidget(label1);
mainlayout->addWidget(label2);
mainlayout->addWidget(label3);
setLayout(mainlayout);}
and this my main.cpp:
#include "widget.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setLayoutDirection(Qt::RightToLeft);
Widget w;
w.show();
qDebug()<<a.layoutDirection() <<w.layoutDirection();
return a.exec();
}
comment: my project uses a stylesheet file and after playing with different parts of style for QComboBox I realized that the style "QComboBox{padding: 0 10 0 10;}" was causing the problem. So I included that, here. If I remove that line the problem will be solved.
note: I also realized that theWidget->setLayoutDirection(Qt::LeftToRight); will do what I was looking though I don't know it's the proper way or not!
So, The Problem was with the stylesheet that my app is using. this line of stylesheet "QComboBox{padding: 0 10 0 10;}" was the cause of problem. I removed it and problem solved. Though I don't know the reason.
Also for a specific widget that shouldn't get the app's layout-direction, the layout-direction must be set explicitly. like: theWidget->setLayoutDirection(Qt::LeftToRight);
And I realized it from Qt documentaion

Button is not showing on main window even after successful execution of code in Qt

I have tried this code but the button isn't displaying on the main window.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QGridLayout>
#include<QLabel>
#include<QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPushButton *l=new QPushButton();
l->setText("abc");
QGridLayout *q=new QGridLayout();
q->addWidget(l);
this->setLayout(q);
this->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
I have tried to change the code even by passing enums for alignment but nothing worked.
When you create new Qt widgets Application, the default form (MainWindow ui) is created with centralWidget to put all other widgets. In your code you created the QGridLayout without a parent, typically such layout should be placed in ui->centralWidget (as far as you are not creating another widget to be set as centralWidget), moreover I assume your mainWindow is shown from main.cpp (need not use show()). your code could thus be:
QPushButton *l=new QPushButton();
l->setText("abc");
QGridLayout *q=new QGridLayout(ui->centralWidget);
q-> addWidget(l);
Try adding the widget to the GridLayout with index using addWidget function
void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = ...)
like:
q-> addWidget(l, 0, 0);
P.S. also consider using better names for your variables!

How to have a QTextBrowser to display contents of a QTextEdit?

I am trying to connect QTextEdit to QTextBrowser, so the text browser widget outputs what is entered in text edit widget. As a signal I used textChanged(), and as a slot I used setText(QString). And these two don't have same parameters.
If I used QLineEdit instead of QTextEdit, in that case there is textChanged(QString) function which is compatible with the slot,but I need to make it work with QTextEdit. Here is the code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QWidget * mainWidget=new QWidget(this);
ui->setupUi(this);
QTextEdit * mainTextEdit=new QTextEdit();
QTextBrowser * textDisplay=new QTextBrowser();
connect(mainTextEdit,SIGNAL( textChanged() ),
textDisplay,SLOT( setText(QString) ) );
QHBoxLayout * Alayout=new QHBoxLayout();
Alayout->addWidget(mainTextEdit);
Alayout->addWidget(textDisplay);
mainWidget->setLayout(Alayout);
setCentralWidget(mainWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
Thankfully, the QTextEdit and QTextBrowser are views onto a QTextDocument model. So, you can simply set the editor's document on the browser. QTextBrowser::setDocument is semantically equivalent to QAbstractItemView::setModel:
textDisplay->setDocument(mainTextEdit->document());
In Qt, there are really two basic model classes: QAbstractItemModel and QTextDocument. A QTextDocument is a model in its own model-view framework. We simply set another view onto the document that the editor operates on. The editor allows modifications to the model, the browser doesn't. It's no different from using the same model on two QListViews, etc.
A QTextEditor is a view with a default model (document). You can replace that default model with one from another view, or even with one that you yourself provide. You could have multiple editors all displaying the same QTextDocument document and allowing editing of it, in parallel. You can also have multiple browsers doing the same.
Complete example:
#include <QApplication>
#include <QTextEdit>
#include <QTextBrowser>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QHBoxLayout layout(&window);
QTextEdit edit;
QTextBrowser browser;
layout.addWidget(&edit);
layout.addWidget(&browser);
browser.setDocument(edit.document());
window.show();
return a.exec();
}
I would do it in the following way:
Declare the pointers to the text edit and text browser widgets as member variables in the class,
Create a slot onTextChanged() in MainWindow class that will be called as soon as the text edit is changed and setup the connection as:
connect(mainTextEdit, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
Implement the onTextChanged() slot in the following way:
MainWindow::onTextChanged()
{
QString text = mainTextEdit->toPlainText();
textDisplay->setPlainText(text);
}

Basic Qt layout: Adding to a frame

I am just staring Qt, so hopefully is a rookie question. Working in Qt Creator 2.7.2, Qt 5, standard desktop app.
Currently my app is one window, with the main window entirely taken up by a console object, with is just a plain text edit, like this:
setCentralWidget(console);
Which of course takes up the entire window. So I added a frame using the UI editor, frame_2. How do I get the console to appear inside the frame, instead of taking up the whole window?
http://qt-project.org/doc/qt-4.8/designer-layouts.html
http://qt-project.org/doc/qt-4.8/layout.html
Your central widget is just QWidget, and then it needs a layout. You drag a layout into it, and there are some buttons across the top of Qt Designer for turning on and off the layout.
When setupUi is called, it already does the setCentralWidget call for you. If you call it yourself you lose all you gained from using Qt Designer.
ui->setupUi(this);
If you are using Qt Designer, you should not edit any generated files. If you edit the .ui file again, it may generate the ui_.h file for you again and fix the problem.
Here is an example of the generated file ui_mainwindow.h:
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created: Wed Jul 10 15:48:32 2013
** by: Qt User Interface Compiler version 4.8.4
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QMenuBar *menuBar;
QToolBar *mainToolBar;
QWidget *centralWidget;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(400, 300);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(mainToolBar);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
// !!!!! NOTE !!!!! setCentralWidget gets called
MainWindow->setCentralWidget(centralWidget);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
I also rambled about using Layouts on a previous post:
Add QRadioButton into QWidget without layout
Hope that helps.

qt: How to animate the transparency of a child QPushButton using QPropertyAnimation?

I want to progressively decrease the opacity of a QPushButton over a time of 2 seconds to complete transparency. For that I used the QPropertyAnimation class and used the property "windowOpacity" of the button to achieve the effect. But that worked only for a standalone QPushButton. When I assigned a parent to the button, the effect disappeared. Is there any way of achieving the same effect for child buttons ?
The windowOpacity property only applies to top level windows so it won't help you with animating transparency on child widgets unfortunately.
Standard controls are a bit problematic as well as there are many considerations contributing to their final appearance. There are many approaches you could take but they will all involve a certain amount of coding. There is no easy way :)
To set the transparency of a QPushButton, you would need to either set a stylesheet for it, or change some of the properties of the palette. Since neither of these options are directly usable by a QPropertyAnimation, you can create your own custom property and animate that.
Below is some code that specifies a custom property for a MainWindow called alpha. The alpha value is used to set the alpha portion of the button color. With this property in place, we can use QPropertyAnimation to animate it. The result is a button that fades in and out. This only handles the buttons background and not the text but it should provide a starting point for you.
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QPushButton>
class MainWindow : public QWidget
{
Q_OBJECT
Q_PROPERTY(int alpha READ alpha WRITE setAlpha);
public:
MainWindow();
virtual ~MainWindow();
private:
int m_alpha;
QPushButton * m_button1, *m_button2;
int alpha() const;
void setAlpha(const int a_alpha);
};
#endif /* MAINWINDOW_H */
MainWindow.cpp: (Updated to include stylesheet transparency example)
#include <QPlastiqueStyle>
#include <QPropertyAnimation>
#include "MainWindow.h"
MainWindow::MainWindow() :
m_button1(0),
m_button2(0),
m_alpha(255)
{
resize(200, 200);
QPalette windowPalette(palette());
windowPalette.setBrush(QPalette::Background, QBrush(QColor(200, 0, 0)));
setPalette(windowPalette);
m_button1 = new QPushButton(this);
m_button1->setText("Palette Transparency");
m_button1->setAutoFillBackground(false);
// NOTE: Changing the button background color does not work with XP Styles
// so we need to use a style that allows it.
m_button1->setStyle(new QPlastiqueStyle());
m_button2 = new QPushButton(this);
m_button2->move(0, 50);
m_button2->setText("Stylesheet Transparency");
m_button2->setAutoFillBackground(false);
m_button2->setStyle(new QPlastiqueStyle());
QPropertyAnimation *animation = new QPropertyAnimation(this, "alpha");
animation->setDuration(1000);
animation->setKeyValueAt(0, 255);
animation->setKeyValueAt(0.5, 100);
animation->setKeyValueAt(1, 255);
animation->setLoopCount(-1);
animation->start();
}
MainWindow::~MainWindow()
{
}
int MainWindow::alpha() const
{
return m_alpha;
}
void MainWindow::setAlpha(const int a_alpha)
{
m_alpha = a_alpha;
QPalette buttonPalette(m_button1->palette());
QColor buttonColor(buttonPalette.button().color());
buttonColor.setAlpha(m_alpha);
buttonPalette.setBrush(QPalette::Button, QBrush(buttonColor));
m_button1->setPalette(buttonPalette);
QString stylesheet("background-color: rgba(0,200,0," + QString::number(m_alpha) + ");");
m_button2->setStyleSheet(stylesheet);
}
main.cpp:
#include <QtGui/QApplication>
#include "MainWindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow m;
m.show();
return app.exec();
}
I faced the same problem a while ago and came to basically the same solution(manipulating the controls palette). But, while the helper property in the MainWindow is surely a quick and easy solution, it's a dirty one too. So, at least for larger and reoccurring usage it seamed much more appropriate to create a new animation class covering those needs. This isn't much more code(simply inherit QAbstractAnimation, move that palette stuff in there and pass the target control as a parameter into that class) but it keeps your parent control(like the mainwindow-class) free from such animation implementation details which surely don't belong in there.

Resources