QLineEdit`s QCompleter stylesheet - c++

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();
}

Related

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

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

Connecting selection of row in 2 QTableWidget

I am trying to connect row selections from two QTableWidget.
I mean, when I select one row in Table 1, I want my program selects the same row in table 2. The two table dont have the same number of column so I cannot just select one item for the first and select the same item on the second able.
I have tried to use the following without success:
connect(ui->table1->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), ui->table2->selectionModel(), SLOT(setCurrentIndex(QModelIndex)));
It is written:
QObject::connect: No such slot QItemSelectionModel::setCurrentIndex(QModelIndex)
Do you know what is going wrong?
The problem is caused because setCurrentIndex() has two parameters, and not just one, plus the signatures do not match. So in these cases you should use a lambda and use selectRow():
#include <QApplication>
#include <QHBoxLayout>
#include <QTableWidget>
#include <QItemSelectionModel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto *table1 = new QTableWidget(4, 3);
table1->setSelectionBehavior(QAbstractItemView::SelectRows);
auto table2 = new QTableWidget(4, 4);
table2->setSelectionBehavior(QAbstractItemView::SelectRows);
QObject::connect(table1->selectionModel(), &QItemSelectionModel::currentRowChanged,
[table2](const QModelIndex &current, const QModelIndex & previous)
{
if(previous.isValid())
table2->selectRow(current.row());
});
QWidget w;
auto lay = new QHBoxLayout(&w);
lay->addWidget(table1);
lay->addWidget(table2);
w.show();
return a.exec();
}

QSplitter - changing the size of QTabWidget

I currently have a QTabWidget and some layout.
Now I want all the tabs of my QtabWidget to occupy the width of the QtabWidget so I have something like this. The following method expands the two tabs in my Qtabwidget so they are the same size as the QtabWidget
void Contacts::AdjustTabs( int pos, int index )
{
std::string orig_sheet = ui.tabWidget->styleSheet().toStdString();
QString new_style = QString("QTabBar::tab { width: %1px; } ").arg((ui.tabWidget->size().width() /ui.tabWidget->count()));
std::string t = new_style.toStdString();
orig_sheet = orig_sheet + t;
ui.tabWidget->setStyleSheet(orig_sheet.c_str());
}
The above method works fine. Now the problem starts when the QTabwidget is set in a Qsplitter layout along with some other layout.At startup construction the above method does not seem to work for instance I have something like this
Someclass::SomeConstructor()
{
ui.setupUi(this);
.........
QObject::connect(ui.splitter,SIGNAL(splitterMoved(int,int)),this,SLOT(AdjustTabs(int,int)));
AdjustTabs(0,0);
}
Now when the form appears the horizontal size of the tabs remain unchanged (they do not expand - which is wrong). However when i move the splitter the tabs expand and everything is fine. My question is how can I make my tabs expand during form load ? Why arent they expanding ?
I think trying to explicitly adjust the tabs' sizes whenever a resize event occurs isn't the best approach. If things are set up properly, the appropriate size adjustments should naturally occur due to the default behavior of the QSplitter and QTabWidget's internal layout managers. Here is a very simple example of what I mean; note that there is no code in this program to explicitly handle resizing of anything, and yet all the tabs resize correctly as the splitter is moved and/or the window is resized:
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QSplitter>
#include <QTabWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow mw;
QSplitter * splitter = new QSplitter(&mw);
QTabWidget * tab = new QTabWidget;
tab->addTab(new QPushButton("Content of tab #1"), "tab #1");
tab->addTab(new QPushButton("Content of tab #2"), "tab #2");
tab->addTab(new QPushButton("Content of tab #3"), "tab #3");
splitter->addWidget(tab);
splitter->addWidget(new QPushButton("Some other content"));
mw.setCentralWidget(splitter);
mw.show();
return a.exec();
}
So the question becomes -- why aren't your tabs resizing themselves automatically? Perhaps there you have their sizePolicy property set to Fixed, rather than Preferred or Ignored?

QTreeView / QFileSystemModel set header labels

Pretty simple task but I didn't manage to find anything useful in documentation. I want a QTreeView to contain a single column called "Files" with data from QFileSystemView. Here's what I've got:
QFileSystemModel *projectFiles = new QFileSystemModel();
projectFiles->setRootPath(QDir::currentPath());
ui->filesTree->setModel(projectFiles);
ui->filesTree->setRootIndex(projectFiles->index(QDir::currentPath()));
// hide all but first column
for (int i = 3; i > 0; --i)
{
ui->filesTree->hideColumn(i);
}
That gives me a single column with "Name" header. How do I rename this header?
QAbstractItemModel::setHeaderData() should work. If not, you can always inherit from QFileSystemModel and override headerData().
Quick but a little dirty trick (please note w.hideColumn()):
#include <QApplication>
#include <QFileSystemModel>
#include <QTreeView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTreeView w;
QFileSystemModel m;
m.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
m.setRootPath("C:\\");
w.setModel(&m);
w.setRootIndex(m.index(m.rootPath()));
w.hideColumn(3);
w.hideColumn(2);
w.hideColumn(1);
w.show();
return a.exec();
}
You can subclass QFileSystemModel and overide method headerData(). For example, if you want only to change first header label and leave the rest with their original values, you can do:
QVariant MyFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const {
if ((section == 0) && (role == Qt::DisplayRole)) {
return "Folder";
} else {
return QFileSystemModel::headerData(section,orientation,role);
}
}

Qt splitter disable

I want to be able to stop a user from moving a QSplitter at runtime. Calling setEnabled(false) does this, but it also disables all child widgets - which isn't what I want. Is there a way to achieve this? Do I have to disable the splitter, and then manually re-enable all child widgets? That seems rather cumbersome, for something that must be a reasonably common practise.
Can anyone suggest anything?
Do this:
for (int i = 0; i < splitter->count(); i++)
{
QSplitterHandle *hndl = splitter->handle(i);
hndl->setEnabled(false);
}
Actually, I've never seen anyone ever disable a splitter: They are there so the user can layout the UI as she needs, so why would anyone want to disable this? Either you need a splitter or you can use one of the normal layouts (which the user can't resize).
If you still want to try, I think you should look at closestLegalPosition() or getRange(). If you just return the width of the widget, then resizing should stop working.
You have to do two things. Set the widgets (that shouldn't be resizeable) inside the splitter to FixedSize and change the cursor of the correspondent splitter handles to Qt::ArrowCursor. The handles start with zero (left and not used), so the first handle between two widgets is by index 1.
Here's a sample (put the code in main.cpp):
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
window.resize(800, 300);
window.setWindowTitle("Splitter Test");
window.show();
QSplitter *splitter = new QSplitter(&window);
QListView *listview = new QListView;
QTreeView *treeview = new QTreeView;
QTextEdit *textedit = new QTextEdit;
splitter->addWidget(listview);
splitter->addWidget(treeview);
splitter->addWidget(textedit);
splitter->setChildrenCollapsible(false);
splitter->show();
listview->show();
treeview->show();
textedit->show();
//make the lisview 'fix'
listview->setFixedSize(listview->width(), listview->height());
//change the cursor over the splitter handle between listview and
//treeview to ArrowCursor
splitter->handle(1)->setCursor(Qt::ArrowCursor);;
return app.exec();
}
Now the first splitter handle is disabled and the second works.