[Qt][C++] setMinimumWidth and setMaximumWidth not working on label - c++

I have label created and want tooltip over it, I want to set tooltip's maximum and minimum width but somehow its not working.
I am not expert to QT, not able to figure out the reason.
Code:
#include "widget.h"
#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>
#include <QLabel>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QListWidget listWidget;
listWidget.setContentsMargins(QMargins(0, 0, 0, 0));
for (int i = 0; i < 5; ++i)
{
QListWidgetItem* item = new QListWidgetItem();
auto *itemWidget = new QWidget();
auto *textLabel = new QLabel(QString("Item %1").arg(i + 1), itemWidget);
textLabel->setMinimumWidth(100); //Not working whatever value I set
textLabel->setMaximumWidth(400); //Not working whatever value I set
textLabel->setToolTip("<p>This is the looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonggggggggggggggg name </p>");
listWidget.addItem(item);
listWidget.setItemWidget(item, itemWidget);
}
listWidget.show();
return a.exec();
}
Tooltip:
can someone please help.

You cant directly set max and min on tooltip , hence you should indrectly do that(for this usecase):
static const QString FORMATTER = "<p>%1</p>";
QString tooltip =
"This is the "
"looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
"oooooooooooooooooonggggggggggggggg name.";
static constexpr auto maximum = 10;
textLabel->setToolTip(FORMATTER.arg(tooltip.mid(0, maximum)));
Update:
if you want exactly have your widget with any properties for tooltip , you can override your events and show the ToolTipWidget that reimplemented.
i.e: Qt WIdget inside ToolTip

textLabel->setMinimumWidth(100);
textLabel->setMaximumWidth(400);
This will set the min/max width of the label itself not the tooltip.
If you want to customize tooltip behavior, you'll have to override the event() function to catch QEvent::ToolTip (and probably QEvent::ToolTipChange) and draw it yourself using QToolTip::showText()

please use :textLabel->setToolTip

Related

How to connect two QComboBox so that the second shows only certain items?

I have two QComboBoxes to connect with each other.
In particular, I'd like that if a scaling is made in the first QComboBox, this is not also shown in the second QComboBox and vice versa..
This is my code:
auto lingua_originaleT = new QComboBox();
lingua_originaleT->addItems({"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"});
auto lingua_targetT = new QComboBox();
lingua_targetT->addItems({"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"});
The result should be like this:
The same language should not appear in the second drop-down menu as well
One possible solution is to use QSortFilterProxyModel to do the filtering:
#include <QApplication>
#include <QComboBox>
#include <QHBoxLayout>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QWidget>
class FilterProxyModel: public QSortFilterProxyModel{
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const{
if(filterRegExp().isEmpty())
return true;
return !QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
widget.resize(640, 480);
widget.show();
QStandardItemModel *model = new QStandardItemModel(&widget);
const QStringList values{"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"};
for(const QString & value: values){
model->appendRow(new QStandardItem(value));
}
QComboBox *lingua_originaleT = new QComboBox;
FilterProxyModel *proxy_originalT = new FilterProxyModel(&widget);
proxy_originalT->setSourceModel(model);
lingua_originaleT->setModel(proxy_originalT);
QComboBox *lingua_targetT = new QComboBox;
FilterProxyModel *proxy_targetT = new FilterProxyModel(&widget);
proxy_targetT->setSourceModel(model);
lingua_targetT->setModel(proxy_targetT);
QHBoxLayout *lay = new QHBoxLayout(&widget);
lay->addWidget(lingua_originaleT);
lay->addWidget(lingua_targetT);
QObject::connect(lingua_originaleT, &QComboBox::currentTextChanged, proxy_targetT, &FilterProxyModel::setFilterFixedString);
QObject::connect(lingua_targetT, &QComboBox::currentTextChanged, proxy_originalT, &FilterProxyModel::setFilterFixedString);
lingua_originaleT->setCurrentIndex(0);
lingua_targetT->setCurrentIndex(1);
return a.exec();
}
Internally, QCombobox uses QStandardItemModel - unless you provided a custom one using setModel().
That means you can do things like:
// Just some setup
auto combo = new QComboBox(this);
combo->addItems({ "Item0", "Item1", "Item2" });
// Here is the interesting bit
auto model = qobject_cast<QStandardItemModel*>(combo->model());
auto item = model->item(0); // <-- index in the combobox
item->setEnabled(false); // <-- You can't select it anymore
if(combo->currentIndex() == 0) // Choose another one if it's already selected
combo->setCurrentIndex(1);
// From now, Item 0 will be visible in the dropdown but not selectable by the user.
I leave you find a way to get the 2 boxes disabling each other items (And importantly, enabling them back once if the selection change). This is a matter of listening the index changed signals of each boxes and and updating the other model accordingly.
I solved and the solution works perfectly!
Here's how I did it:
lingua_originaleT = new QComboBox();
lingua_targetT = new QComboBox();
QStringList traduzioneLangList = {"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"};
lingua_originaleT->clear();
lingua_originaleT->addItems(traduzioneLangList);
lingua_originaleT->setCurrentIndex(-1);
lingua_targetT->clear();
lingua_targetT->addItems(traduzioneLangList);
lingua_targetT->setCurrentIndex(-1);
connect(lingua_originaleT, &QComboBox::currentTextChanged, lingua_targetT, [=](const QString &selection) {
auto tarLangList = traduzioneLangList;
lingua_targetT->blockSignals(true);
tarLangList.removeOne(selection);
lingua_targetT->clear();
lingua_targetT->addItems(traduzioneLangList);
lingua_targetT->blockSignals(false);
});
connect(lingua_targetT, &QComboBox::currentTextChanged, lingua_originaleT, [=](const QString &selection) {
auto tarLangList = traduzioneLangList;
lingua_originaleT->blockSignals(true);
tarLangList.removeOne(selection);
lingua_originaleT->clear();
lingua_originaleT->addItems(traduzioneLangList);
lingua_originaleT->blockSignals(false);
});
lingua_originaleT->setCurrentIndex(0);
Many thanks to #lifof on reddit!

QLineEdit`s QCompleter stylesheet

Having a QLineEdit with a plain vanilla QStringList QCompleter. I wonder if I can change the appearance of the dropdown (I want to have either a min. size or smaller scrollbar).
Clarification: I want to set it in a stylesheet, not in the code.
Summary of my findings so far:
Pretty good summary here: https://forum.qt.io/topic/26703/solved-stylize-using-css-and-editable-qcombobox-s-completions-list-view/12
I have to use QStyledItemDelegate and
give the popup a name for the qss selector
I have tried that and it does not work for me, but seems to work for others
A simple straight forward solution is to set the stylesheet of the QScrollBar used by the popup of the QCompleter. My knowledge of qss is little, so I don't know if you can set a minimum size that way, but you can always have a look at verticalScrollBar().
Here is some code for the qss way:
#include <QAbstractItemView>
#include <QCompleter>
#include <QLineEdit>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineEdit edit;
edit.show();
QStringList completionList;
for (int a = 0 ; a < 10 ; ++a) {
completionList << QString("test%1").arg(a);
}
QCompleter completer(completionList);
edit.setCompleter(&completer);
QAbstractItemView *popup = completer.popup();
popup->setStyleSheet("QScrollBar{ width: 50px;}");
return a.exec();
}

Accessing the variables of a parent widget via a button

I'm trying to implement a default button. This button should access strings of the parent widget which is a dialog box which the button is found on. I pasted the relevant parts of the code below. What I want is to be able to place strings to their corresponding lineEdit's when default values is clicked. For example pulse_string goes to ui->pulse_freq and nr_pulsestring goes into ui->nr_pulses etc.
#include "settings.h"
#include "ui_settings.h"
#include <QLineEdit>
#include <QSlider>
#include <QSpinBox>
int pulse_freq = 25000;
int nr_pulses = 10;
int samp_freq = 150000;
int nr_samples = 2000;
int gain = 32;
int accumulate = 1;
int acq_start = 0;
Settings::Settings(QWidget *parent) :
QDialog(parent),
ui(new Ui::Settings)
{
QString pulse_string, nr_pulsestring, sampfreq_string, nr_samplestring, gain_string;
QString accumulate_string, acq_string;
}
Settings::~Settings()
{
delete ui;
}
void Settings::on_Default_Values_clicked()
{
ui->pulse_freq->setText("25000");
ui->nr_pulses->setText("10");
ui->samp_freq->setText("150000");
ui->nr_samples->setText("2000");
ui->gain->setText("32");
ui->accumulate->setText("1");
ui->acq_start->setText("0");
}
You can use something looking like follows:
ui->pulse_freq->setText(QString("%1").arg(pulse_freq));
Since it seems you are only using numbers it would be better using a spinbox to insert values, so you dont have to check if an input is a valid number, etc.

Fitting rows in QTableView, getting rid of extra space

I'm trying to generate a simple table (2 rows and 2 columns) and write it to a pdf file, using Qt 4.8.0.
So far, I generate the pdf but there is extra space at the bottom of the "printed" table:
I got the same problem with the right side of the table but I managed to get rid of it. But in this case I am clueless.
Here's the code I have now (all of this code is located in main.cpp):
Main
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtGui/QPrinter>
#include <QtGui/QHeaderView>
#include <QtGui/QPainter>
#include <QtGui/QTableWidget>
#include <QtGui/QTableWidgetItem>
/**/
/* Here are the functions.
/**/
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QMap<QString,int> values;
values.insert("X",7);
values.insert("Y",13);
bool status = TableWidgetToPdf("FromWidget.pdf",values);
return a.exec();
}
TableWidgetToPdf
bool TableWidgetToPdf(const QString& title, const QMap<QString, int>& values) {
QTableWidget* table = GenerateTable(values);
QPrinter printer;
printer.setOutputFileName(title);
printer.setOutputFormat(QPrinter::PdfFormat);
QPainter painter(&printer);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
printer.setPaperSize(QPrinter::A4);
table->render(&painter);
painter.end();
printer.newPage();
delete table;
return true;
};
GenerateTable
QTableWidget* GenerateTable(const QMap<QString,int>& values) {
QTableWidget* table = new QTableWidget;
table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
table->setRowCount(2);
table->setColumnCount(2);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
table->setShowGrid(false);
table->verticalHeader()->hide();
QStringList h_labels;
h_labels << "X" << "Y";
table->setHorizontalHeaderLabels(h_labels);
table->horizontalHeader()->setFont( QFont("Times", 10, QFont::Bold) );
table->horizontalHeader()->setStretchLastSection(true);
QTableWidgetItem* item00 = new QTableWidgetItem( QString::number(values["X"]));
item00->setTextAlignment(Qt::AlignCenter);
table->setItem(0,0, item00 );
QTableWidgetItem* item01 = new QTableWidgetItem( QString::number(values["Y"]) );
item01->setTextAlignment(Qt::AlignCenter);
table->setItem(0,1,item01);
table->setItem(1,0,new QTableWidgetItem("ABCD"));
return table;
};
NOTE:
Putting
table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
in GenerateTable the space disappears, but the cells are resized and consume too much space than needed for their contents. I would like to avoid that if possible:
EDIT:
OK.
In the end I achieved what I wanted by getting rid of the QTableWidget. I had to create the table using html and feeding it to a QTextEditor. Isn't any way to achieve this with a QTableWidget?
Have you tried the flags for resize content?
Try the following code, I don't have access to Qt right now.
table->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
table->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
Hope that works!
I realise that this is an old post but it seems fairly often read.
I tried the same methods that you tried and none worked. Eventually I used a QTableView and added an extra method called by adding/removing rows.
void
TitleView::verticalResizeTableViewToContents()
{
auto count = m_model->rowCount(QModelIndex());
auto scrollBarHeight = horizontalScrollBar()->height();
auto horizontalHeaderHeight = horizontalHeader()->height();
auto rowTotalHeight = scrollBarHeight + (horizontalHeaderHeight * count);
setMinimumHeight(rowTotalHeight);
setMaximumHeight(rowTotalHeight);
}

An issue when creating a pop-up menu w.r.t to a parametr via loop

I am trying to create pop-up menu depending on a variable as follows:
QMenu menu(widget);
for(int i = 1; i <= kmean.getK(); i++)
{
stringstream ss;
ss << i;
string str = ss.str();
string i_str = "Merge with " + str;
QString i_Qstr = QString::fromStdString(i_str);
menu.addAction(i_Qstr, this, SLOT(mergeWith1()));
}
menu.exec(position);
where:
kmean.get(K) returns an int value,
mergeWith1() is some `SLOT()` which works fine
Issue:
The loop creates an action on menu only for i=1 case, and ignores other values of i.
Additional information
When doing the same loop with casual int values (without convert) everything works fine. e.g. if I do in loop only menu.addAction(i, this, SLOT(...))) and my K=4, a menu will be created with four actions in it, named 1, 2, 3, 4 correspondingly.
What can be the problem caused by
I think the issue is in convert part, when I convert i to string using stringstream and after to QString. May be the value is somehow lost. I am not sure.
QESTION:
How to make the loop accept the convert part?
What do I do wrong in convert part?
In Qt code, you shouldn't be using std::stringstream or std::string. It's pointless.
You have a crashing bug by having the menu on the stack and giving it a parent. It'll be double-destructed.
Don't use the synchronous blocking methods like exec(). Show the menu asynchronously using popup().
In order to react to the actions, connect a slot to the menu's triggered(QAction*) signal. That way you can deal with arbitrary number of automatically generated actions.
You can use the Qt property system to mark actions with custom attributes. QAction is a QObject after all, with all the benefits. For example, you can store your index in an "index" property. It's a dynamic property, created on the fly.
Here's a complete example of how to do it.
main.cpp
#include <QApplication>
#include <QAction>
#include <QMenu>
#include <QDebug>
#include <QPushButton>
struct KMean {
int getK() const { return 3; }
};
class Widget : public QPushButton
{
Q_OBJECT
KMean kmean;
Q_SLOT void triggered(QAction* an) {
const QVariant index(an->property("index"));
if (!index.isValid()) return;
const int i = index.toInt();
setText(QString("Clicked %1").arg(i));
}
Q_SLOT void on_clicked() {
QMenu * menu = new QMenu();
int last = kmean.getK();
for(int i = 1; i <= last; i++)
{
QAction * action = new QAction(QString("Merge with %1").arg(i), menu);
action->setProperty("index", i);
menu->addAction(action);
}
connect(menu, SIGNAL(triggered(QAction*)), SLOT(triggered(QAction*)));
menu->popup(mapToGlobal(rect().bottomRight()));
}
public:
Widget(QWidget *parent = 0) : QPushButton("Show Menu ...", parent) {
connect(this, SIGNAL(clicked()), SLOT(on_clicked()));
}
};
int main (int argc, char **argv)
{
QApplication app(argc, argv);
Widget w;
w.show();
return app.exec();
}
#include "main.moc"