How to get the text of a Qcomplete in a Qcombobox - c++

I have a combobox that I fill with a QList and now I have generated a search engine with the help of the QCompleter, so far everything is fine, but I have edited it to make it visually more attractive, and it worked correctly until I have trouble selecting with the mouse one of the options that the QCompleter threw at me and the selection does not respect me, it only respects me if I give an Enter with the keyboard, but only for a moment.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qApp->setStyleSheet("QAbstractItemView#completerPopup {font: 15pt ;color: rgb(255, 255, 255);}");
}
QCompleter *completer = new QCompleter(list, this);
completer->setFilterMode(Qt::MatchContains);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->popup()->setObjectName("completerPopup");
ui->cobobox->setCompleter(completer);
I manage to make it work but I have to remove some lines of code that are the ones that help me edit the QCompleter as Pupop.
QCompleter *completer = new QCompleter(list, this);
completer->setFilterMode(Qt::MatchContains);
completer->setCaseSensitivity(Qt::CaseInsensitive);
ui->cobobox->setCompleter(completer);
The error it throws when I select is the following
Setting a QCompleter on non-editable QComboBox is not allowed.

In the qtcreator form designer select your combobox and in properties window mark editable checkbox.

Related

How to programmatically stop editing QTreeWidget in Qt?

I have a QTreeWidget and two buttons "+" and "-". When I press "+" I want to add new item to QTreeWidget and I want that item to be in edit mode. I managed to do that with following code (it gets called every time "+" is pressed):
// QTreeWidgetItem* lastItem = getLastItem();
// if (lastItem) { widget->closePersistentEditor(lastItem); }
QTreeWidgetItem* item = new QTreeWidgetItem(widget, {"100000"});
item->setFlags(item->flags() | Qt::ItemIsEditable);
widget->addTopLevelItem(item);
widget->editItem(item);
Problem is when I try to add a new item, but don't exit edit mode before adding (press Enter or something). I get error edit: editing failed and new item is added below current item (which is still in edit mode).
What I would like is that current item exists edit mode and that newly added item becomes focused and enters edit mode.
I tried to do that with first getting the last item in a QTreeWidget and calling closePersistentEditor(lastItem) (commented code) and then creating and adding new item, but it didn't work. So, how to close currently opened edit on item?
EDIT:
Ok, I have added additional code with minimal example. Only thing you have to do to build it is to add QTreeWidget and QPushButton to the form mainwindow.ui and connect that button to on_btnAdd_clicked():
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTreeWidget>
#include <QTreeWidgetItem>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnAdd_clicked()
{
QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget, {"100000"});
item->setFlags(item->flags() | Qt::ItemIsEditable);
ui->treeWidget->addTopLevelItem(item);
ui->treeWidget->editItem(item);
}
EDIT2: This is happening on macOS (Mojave) with Qt 5.12.
Ok, it looks like this is a bug in Qt for macOS. Workaround that I did is following:
QTreeWidgetItem* lastItem = getLastTreeWidgetItem(widget);
if (lastItem) {
widget->setDisabled(true);
widget->setDisabled(false);
}
conversation->setFlags(conversation->flags() | Qt::ItemIsEditable);
getLastTreeWidget() is my own method that returns last added item in a QTreeWidget. Now every time when I press button to add new item, previous gets deselected and newly added enters edit mode.

QObject::findChild returns 0 for QLabels added to statusbar

I created a application running in a QMainWindow using qtcreator, so the typical way.
I added two 'manually' (meaning: not with the Form editor) created qlabels to the statusbar:
in the header:
QLabel *label_timestamp;
QLabel *contentLabel_timestamp;
in the constructor:
MainWin::MainWin(const CmdLineOptions &opts, QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWin),
m_connectionStatusLabel(new QLabel),
m_client(new QMqttClient),
m_mqttmanager(new MQTTManager(m_client)),
m_mqttServerName("localhost")
{
ui->setupUi(this);
label_timestamp = new QLabel(this);
contentLabel_timestamp = new QLabel(this);
label_timestamp->setText("system time");
contentLabel_timestamp->setText("dd.mm.yyyy, hh:mm:ss:zzz"); /* just testing output */
statusBar()->addPermanentWidget(label_timestamp);
statusBar()->addPermanentWidget(contentLabel_timestamp);
}
If I do a
Label *label = findChild<QLabel *>(QString("contentLabel_")+objName);
elsewhere in this class implementation with objName being 'timestamp', of course, findChild() returns 0. It's working fine with other QLabels created using QtCreator in the form editor, findChild() finds them all. Isn't the statusbar widget and its content also a child of ui? Does somebody eventually know a way out of there?
I want to use findChild to generically fill my labels following a naming scheme with content I receive over MQTT, this is the background. Would be great if the statusbar content would need a special handling but could also be handled in this dynamic approach.
Thanks a lot
findChild uses the objectName, in the case of Qt Creator this establishes it in the MOC, but in your case you must establish it:
label_timestamp = new QLabel(this);
contentLabel_timestamp->setObjectName("label_timestamp");
contentLabel_timestamp = new QLabel(this);
contentLabel_timestamp->setObjectName("contentLabel_timestamp");
And then you can recover it with:
QLabel *label_1 = findChild<QLabel *>("label_timestamp");
if(label_1){
// some code
}
QLabel *label_2 = findChild<QLabel *>("contentLabel_timestamp");
if(label_2){
// some code
}

QT Making a Dropdown Menu Widget Programmatically

I am using QT 5.5 with Mac OSX. I want to make several dropdown menu widgets programmatically that will have various options that can change the values of certain variables.
So for example, I would have dropdown menu 1 represent variable "command" have:
- Q
- W
- E
- R
And by selecting whichever one, then it would make command = Q, or command = W. So that way, I can send command to another program knowing that I sent Q, or W.
My current mainwindow looks something like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//******* Set up
ui->setupUi(this);
ui->centralWidget->setLayout(new QVBoxLayout);
// 01: Creation of Console
console = new Console;
console->setEnabled(false);
/************** Adding Widgets *********************/
//creation and attribution of slider
slider = new QSlider();
slider->resize(255, 20);
slider->setOrientation(Qt::Horizontal);
slider->setRange(0, 255); //0-255 is range we can read
//creation and attribution of the lcd
lcd = new QLCDNumber();
lcd->setSegmentStyle(QLCDNumber::Flat);
lcd->resize(255, 50);
//03: Adding widgets to layout
//add console as a widget to the main widget
//layout with slider and lcd underneath console
ui->centralWidget->layout()->addWidget(console);
ui->centralWidget->layout()->addWidget(slider);
ui->centralWidget->layout()->addWidget(lcd);
////////I WANT TO ADD VARIOUS DROPDOWN MENUS HERE NEXT TO EACH OTHER////////
/************** Connection Events ***********************/
....
}
Assuming you want a ComboBox, Here is how you can do it:
QStringList commands = { "Q", "W", "E", "R" };
QComboBox* combo = new QComboBox(this);
combo->addItems(commands);
connect( combo, &QComboBox::currentTextChanged, this, &MainWindow::commandChanged);
Now you will get the command text when user changes the combo box item. and you can write your code based on that.
MainWindow::commandChanged(const QString& command_text)
{
//Do the logic based on command_text
}
Another option if you want to choose combobox item texts differently is that you set itemData for combobox items. and get them in your slot by currentData property of the ComboBox.

How to change contents of QMainWindow dynamically

I have a QMainWindow that starts out with nothing but a menubar with a menu that has two options. When the first is clicked the window should be populated with QLabels and various input widgets to recieve data. When the second option is clicked the window should be populated with a QTextEdit(obviously removing whatever was on the window at the time)
The following is code I have tried :
void OrderWindow::displayAddOrder(){
QVBoxLayout* tlayout = new QVBoxLayout();
QHBoxLayout* row = new QHBoxLayout();
row->addWidget(nameLbl);
tlayout->addLayout(row);
qDeleteAll(children());
delete layout();
setLayout(tlayout);
}
It's a bit messy since I've been trying various things. When I click on a menu option with this code it simply says the application has stopped working.
Any help would be appreciated.
You have at least the following options:
Always show the actual widget, and hide the rest. This is simple in case of two widgets like in your example. You could use this technique with the observer design pattern for any number of widgets.
Use the QStackedWidget class which basically behaves the way as your custom observer pattern implementation would be, although you will need to use an extra class for this.
Therefore, I would suggest to write the following code:
orderwindow.h
...
class QStackedWidget;
class OrderWindow
{
...
public:
explicit OrderedWindow(QWidget *parent);
...
private:
QStackedWidget m_stackedWidget;
...
}
...
orderwindow.cpp
#include "orderwindow.h"
#include <QStackedWidget>
...
OrderWindow::OrderWindow(QWidget *parent)
: QWidget(parent)
, m_stackedWidget(new QStackedWidget(this))
{
QWidget *firstPageWidget = new QWidget;
QWidget *secondPageWidget = new QWidget;
m_stackedWidget->addWidget(firstPageWidget);
m_stackedWidget->addWidget(secondPageWidget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(stackedWidget);
setLayout(layout);
}
...
void OrderWindow::displayAddOrder() {
m_stackedWidget->setCurrentWidget(nameLbl);
}
...
you can use a QStackedWidget
start with showing an empty page and then show the correct page as needed:
there is then no need to mess with adding or removing widgets
Yes, you can use a QStakedWidget if your input options are fixed. If it's not, I suggest you to use an abstract factory pattern to create the stacked widget content. This woluld make your code more readable.

Setting the form lines like iTunes info dialog on Mac with Qt

I'm just a beginner and I wonder if it would be possible to create a form widget on Mac like the info dialog in iTunes.
I tried using:
QGroupBox: I cannot find a way to get rid of the frames.
Creating my own widget: I cannot find a way to fix the spacing between the label and the QLineEdit widget using the QVBoxLayout (actually I'm not sure I understand well the differences between margin/spacing).
QFormLayout: I cannot find a way to reduce the size of the QLabel after using setrowWrapPolicy::WrapAllRows
Also I am not (yet) very comfortable with QtDesigner, so i'd like to avoir using it (for now)
Thanks in advance
Edit: Some precisions on the programs. I use QtCreator 2.6.1 with Qt 4.8.1 and 5.0 on Mac OS X Mountain Lion.
Edit 2: Here is the code.
Subclass of QWidget:
MCLineEdit::MCLineEdit(const QString &header)
{
m_lineEdit = new QLineEdit;
m_lineTitle = new QLabel(header);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(m_lineTitle);
layout->addWidget(m_lineEdit);
layout->setSpacing(0);
setLayout(layout);
}
To display the widget
myView::myView(QWidget *parent) :
QWidget(parent)
{
setFixedSize(600, 500);
MCLineEdit *lineEdit1 = new MCLineEdit("Test 1");
MCLineEdit *lineEdit2 = new MCLineEdit("Test 2");
MCLineEdit *lineEdit3 = new MCLineEdit("Test 3");
MCLineEdit *lineEdit4 = new MCLineEdit("Test 4");
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(lineEdit1);
mainLayout->addWidget(lineEdit2);
mainLayout->addWidget(lineEdit3);
mainLayout->addWidget(lineEdit4);
mainLayout->setSpacing(0);
setLayout(mainLayout);
}
This can be accomplished a ton of ways I am sure. Qt gives you all the possible layouts you could need to achieve this. You could do it with a QGridLayout, and add widgets with different amounts of "cell" spanning, and control the row and column sizes to suit. Or you can just do it with a bunch of nested vertical/horizontal layouts.
For example, you can group a label and a field together in a QVBoxLayout, by adding the widgets with a left alignment, and then setting the spacing to 0 between the items:
layout->setSpacing(0);
layout->addWidget(aLabel, Qt::AlignLeft);
layout->addWidget(aLineEdit, Qt::AlignLeft);
mainVerticalLayout->addLayout(layout);
For something like the track numbers, it is just more nested layouts:
vLayout->addWidget(aLabel);
hLayout->addWidget(aCheckbox);
hLayout->addWidget(aLabel);
hLayout->addWidget(aCheckbox);
vLayout.addLayout(hLayout);
And regarding your bullet points:
QGroupBox lets you remove the frame with setFlat(bool)
With layouts, the margin is the padding around the outside of the contained widgets. What you want is setSpacing(int) to control the amount of space between the items in the layout.
QFormLayout is probably not your best choice here. That is usually for having labels on one side and widgets on the other. Basically it is a 2 column layout. A QGridLayout would be more appropriate. And to reduce the size of the QLabel, you can give it a max or a fix size. Such as using setFixedWidth() or setMaximumWidth() on the label.
So I finally managed to get the expected result after playing a bit with QtCreator.
Here is the code for who might be interested:
myLineEdit:myLineEdit(const QString &header)
{
m_lineEdit = new QLineEdit;
m_groupBox = new QGroupBox;
QFont groupFont;
groupFont.setPixelSize(10);
groupFont.setBold(true);
m_groupBox->setTitle(header);
m_groupBox->setFlat(true);
m_groupBox->setFont(groupFont);
m_groupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QFont lineFont;
lineFont.setPixelSize(13);
lineFont.setBold(false);
m_lineEdit->setFont(lineFont);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(m_lineEdit);
layout->setContentsMargins(0, 10, 0, 0);
layout->setSpacing(10);
layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_groupBox->setLayout(layout);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(m_groupBox);
setLayout(mainLayout);
}
One comment though: will only work on Qt 5 since on 4.8 the setFlat() method will display a separating line between the header and the QLineEdit.
Thanks to jdi for his help!