How to get the text of a combobox in a tablewidget? - qt

I’m new to Qt, I need help with getting the value of a combobox in a table widget.
I use “setCellWidget” to add a combobox(in my case, its name is “settingA”) to a table widget (the name is “tableWidget_4”):
QComboBox* settingA = new QComboBox();
settingA->addItem("100");
settingA->addItem("200");
ui->tableWidget_4->setColumnCount(1);
ui->tableWidget_4->setRowCount(3);
ui->tableWidget_4->setCellWidget ( 0, 0, settingA );
What I want to do here is:
When a button (its name is “ApplyComboButton” in my case) is clicked, I want the value of the combobox(settingA) can be saved into a QStringList(InputComboData) , and this is how I try to do this:
void MainWindow::on_ApplyComboButton_clicked()
{
QStringList InputComboData;
InputComboData << ui->tableWidget_4->item(0,0)->text();
}
And it fails.
How can I get the value of my combobox?

You can use the QTableWidget::cellWidget ( int row, int column ) function to get your QComboBox widget. Use qobject_cast to cast it to QComboBox, and use the currentText() function to get the text.
QComboBox *myCB = qobject_cast<QComboBox*>(ui->tableWidget_4->cellWidget(0,0));
InputComboData << myCB->currentText();

Use QTableWidget's cellWidget to get a QWidget* to the widget you set as cellWidget (don't forget to use qobject_cast or dynamic_cast to cast that pointer to a QCombobox*)

Related

How to set data source for a list view to contain custom data ? (and associate with QTableView)

I am trying to get listview and tableview working together.
The listview must be used for display, the tableview must be used for editing data. The tableview is created on demand in a popup widget (and it may never be needed).
I populate the listview, on start, from a text file - each row a line, with 2 entries separated by a tab. Easy.
The tableview will have to edit 2 columns separately... also, on listview click, I must be able to retrieve the first part of the split...
I have created a model subclass of QStringListModel.
QListView *m_myView = new QListView();
StringList *m_myList = new StringList();
QTextStream in(&myFile);
while (!in.atEnd())
{
QString temp = in.readLine();
if(!temp.isEmpty())
m_myList->append(temp);
}
myFile.close();
m_myView->setModel(m_myList);
where
class StringList : public QStringListModel
{
public:
void append (const QString& string)
{
insertRows(rowCount(), 1);
QModelIndex m = index(rowCount() - 1);
setData(m, string, Qt::EditRole);
QStringList splist = string.split('\t');
setData(m, splist.at(0), Qt::ToolTipRole);
if(splist.size() > 1)
setData(m, splist.at(1), Qt::StatusTipRole);
else
setData(m, "", Qt::StatusTipRole);
qDebug() << data(m, Qt::EditRole).toString()
<< data(m, Qt::ToolTipRole).toString()
<< data(m, Qt::StatusTipRole).toString();
}
};
The EditRole displays correctly, the others display empty strings.
It seems that QStringListModel is incapable of storing anything except EditRole.
So I am left with 2 options - either do the split on each selection, and also when creating the table view, or - what I would like to try but don't know how - create a QStandardItemModel that can act as data sources for both the listview and the tableview, and can easily retrieve the partial data I require on click.
I thought I can simply use it to set the data on listview (like they do here).
QListView *m_myView = new QListView();
QStandardItemModel *m_myList = new QStandardItemModel();
QTextStream in(&myFile);
int r = 0;
while (!in.atEnd())
{
QString temp = in.readLine();
if(!temp.isEmpty())
{
QStringList splist = temp.split('\t'); // assume I know there will be 2 strings always
QStandardItem *item = new QStandardItem(splist.at(0));
m_myList->setItem(r, 0, item);
QStandardItem *item1 = new QStandardItem(splist.at(1));
m_myList->setItem(r, 1, item1);
++r;
}
}
myFile.close();
m_myView->setModel(m_myList);
connect(m_myListView, SIGNAL(clicked(QModelIndex)),
this, SLOT(listChangedSlot(QModelIndex)));
But this will only set the first string in the listview, I really need both, and I still don't know how to retrieve the data
void listChangedSlot(QModelIndex index)
{
qDebug() << m_myList->item(index.row(), 0)->data().toString()
<< m_myList->item(index.row(), 1)->data().toString();
} // shows empty strings
Or...
In the loading section, try:
if(!temp.isEmpty())
{
QStringList splist = temp.split('\t');
splist.append(QString()); // so I don't need to test
QStandardItem *item = new QStandardItem(temp);
m_myList->setItem(r, 0, item);
QModelIndex idx = m_myList->index(r, 0);
QMap<int, QVariant> roles;
roles.insert(Qt::UserRole + 1, QVariant(splist.at(0)));
roles.insert(Qt::UserRole + 2, QVariant(splist.at(1)));
roles.insert(Qt::DisplayRole, QVariant(temp));
m_myList->setItemData(idx, roles);
++r;
}
This works - displays fine and gets the correct content on click - but seems to be unusable for the tableview.
(And seems I am doing twice the work, with setItem and setItemData - so technically storing the content 3 times).
How can I get my listview have a datasource with 2 string items, show both, be able to set it on a tableview, and be able to retrieve the first item on click ?
I figured out a way to share the data source between the listview and tableview:
I create 3 columns - column 0 with the combined components, and columns 1 and 2 with the separated components.
The listview will display only column 0. For tableview, I will hide column 0.
The data I require for processing will be stored in columns 1 and 2. user edit of the data in tableview will require, upon accepting changes, the edit of corresponding column 0.

How to get the text on qpushbutton?

I am loading .ui files via QUiloader, and showing the GUI in my application.
QWidget *mywidget = loader.load(file, this);
QList<QWidget*> wlist = mywidget.findChildren<QWidget *>()
I would like to know what is the text on QPushbutton. I know there is a method text() to get a text from Pushbutton, but it is not accessible when I do:
QString btext = wlist.at(1).text();
Any idea how I can get the text from QPushbutton, and other Widgets, when they grouped as QWidget?
Thanks.
You should search for QPushButtons instead of QWidgets:
QList<QPushButton*> blist = widget.findChildren<QPushButton*>();
Still your code wouldn't compile. The last line should read:
QString btext = blist.at(1)->text();
Using -> since you are accessing a pointer, not the widget. Also you should check if the findChildren() function actually returnes enough buttons. You would get a crash or assertions when accessing a list item by an invalid index.
Also please note that at(1) does not return the first but the second item in the list (lists start from 0).
Update: If you search for QWidgets and cast each of them you need to take care of getting a nullptr:
QList<QWidget*> wlist = widget.findChildren<QWidget*>();
foreach (QWidget* w, wlist)
{
QPushButton* b = dynamic_cast<QPushButton*>(w);
// If "w" is not a button "b" is nullptr
if (b)
{
QString btext = b->text();
}
}

Qt How to check state checkbox in QtableWidget

Recently I found the way that checkbox places in the middle of QtableWidget item.
However, I do not know how to check state whether or not button is clicked.
Could you tell me how to check button state?
here is what Ive found code:
QWidget *pWidget = new QWidget();
QCheckBox *pCheckBox = new QCheckBox();
QHBoxLayout *pLayout = new QHBoxLayout(pWidget);
pCheckBox->setCheckState(Qt::Checked);
pLayout->addWidget(pCheckBox);
pLayout->setAlignment(Qt::AlignCenter);
pLayout->setContentsMargins(0,0,0,0);
pWidget->setLayout(pLayout);
ui->tableWidget2->setCellWidget(2,2, pWidget);
Although this is very late you can solve it like this:
auto field = ui->tableWidget2->cellWidget(2, 2, pWidget);
std::cout << qobject_cast<QCheckBox*>(field)->isChecked() << std::endl;
This works for other types as well (QComboBox etc.). Although it would probably be better to just use the checkbox functionality that QTableWidgetItem already has.
This example might not work if you are using a tristate checkbox in which case you should call: checkState() and compare it to Qt::CheckState. If qobject_cast<T> does not work out you can use a reinterpret_cast<T>.
I assume you created your checkboxes in the QWidgetTable like this:
int row...;int column...;
...
QTableWidgetItem *checkBoxItem = new QTableWidgetItem();
checkBoxItem->setCheckState(Qt::Unchecked);
ui->Table->setItem(row, column, checkBoxItem);
You can check the status of the item that corresponds to your widget in another function like this:
void MainWindow::on_Table_cellClicked(int row, int column)
{
QTableWidgetItem *checkBoxState = ui->Table->item(row, column);
if(ui->Table->item(row,column)->checkState())
{
checkBoxState->setCheckState(Qt::Unchecked);
ui->Table->setItem(row, column, checkBoxState);
}
else
{
checkBoxState->setCheckState(Qt::Checked);
ui->Table->setItem(row, column, checkBoxState);
}
}

Qt - how to access QComboBox data inserted in QTreeWidget

During runtime I have inserted QCombobox in my QTreeWidget like this:
//global defines
#define COLUMN_1 (0)
#define COLUMN_2 (1)
//Init QComboBox to QTreeWidget - works fine.
QTreeWidgetItem *item = new QTreeWidgetItem(_myTreeWidget);
item->setText(COLUMN_1,"testing");
QComboBox *box = new QComboBox();
box->addItem("select1");
box->addItem("select2");
box->addItem("select3");
_myTreeWidget->setItemWidget(item, 1, box);
The above code works, but I also want to read the data text in these columns. Eg. get the strings "testing" & "select2" from code above. The problem is that I can't figure out how to read the "QComboBox::currentText()" in the comboboxes.
I have tried:
QTreeWidgetItemIterator it(_myTreeWidget);
while(*it)
{
QTreeWidgetItem *item = *it;
QVariant first = item->text(COLUMN_1);
QString firstStr = loggerName.toString(); //this works
QComboBox *box = (QComboBox*)item->data(COLUMN_2, 0);
QString boxValStr = box->text().toString(); //this doesn't works, always empty string
//... more code to handle strings...
it++;
}
Feels like the "item->data(COLUMN_2, 0)" is wrong way to go cause it returns a QVariant.
Solution on this problem?
QComboBox *box = (QComboBox*)item->data(COLUMN_2, 0);
When I read this code, I went into panic mode. Look at the signature:
QVariant QTreeWidgetItem::data ( int column, int role ) const
As you used setItemWidget, you should probably use
QWidget * QTreeWidget::itemWidget ( QTreeWidgetItem * item, int column ) const
ps: If you want to cast, use C++ casts. Much better, use qobject_cast<SubtypeofQObjectPtr> for QObject. It returns null when the cast is invalid.
Indeed, I mean retrieve the combobox using a call similar to :
QComboBox* box = qobject_cast<QComboBox*>(treeWidget->itemWidget(item, column));
Solved it thanks to the help from #Umnyobe and #Zaiborg above. Here is a total working example:
Init QTreeWidget with text in column1 and QComboBox in column2:
//global defines
#define COLUMN_1 (0)
#define COLUMN_2 (1)
QTreeWidgetItem *item = new QTreeWidgetItem(_myTreeWidgetPtr);//item to put in tree
item->setText(COLUMN_1,"animal"); //item for column 1 in the tree.
QComboBox *box = new QComboBox();
box->addItem("mouse"); //adds selections for comboboxes
box->addItem("cat");
box->addItem("dog");
_myTreeWidgetPtr->setItemWidget(item, COLUMN_2, box); //insert items in tree.
Read values from tree:
QTreeWidgetItemIterator it(_myTreeWidgetPtr);
while(*it)
{
QTreeWidgetItem *item = *it;
//Init pointer to current combobox
QComboBox* box = qobject_cast<QComboBox*>(_myTreeWidgetPtr->itemWidget(item, COLUMN_2));
//Get data from QTreeWidget
QString col1Str = item->text(COLUMN_LOGGER);
QString col2Str = box->currentText();
it++;
}
hope it can help someone :)
use the QSignalMapper class to collect the different boxes in the treewidget.
then connect the QSignalMapper::mapped() signal to some slot and use the combobox
edit:
QSignalMapper* mapper = new QSignalMapper(this);
QComboBox *box = new QComboBox();
connect( box, SLOT(/*whatever*/), mapper, SLOT( map() ) );
mapper->setMapping( box );
myTreeWidget->setItemWidget(item, 1, comboBox);
For anyone who is looking for a Python solution,
(PySide / PyQt QComboBox in QTreeWidget), here is it:
item = QTreeWidgetItem(self.treeWidgetAnimals)
item.setText(0, "animal")
combo_box = QComboBox()
combo_box.addItem('mouse')
combo_box.addItem('cat')
combo_box.addItem('dog')
self.treeWidgetAnimals.setItemWidget(item, 1, combo_box)
I was looking for hours but no other forum like pass reference "parent" like a "delegation":
        item = QTreeWidgetItem (self.myTreeWidgetItemObject)
if you do not pass the parent, error ir not returned but the ComboBox not appears in display TreeWidget.

How to make QPushButtons to add text into QLineEdit box?

I used Qt Creator to make a "keyboard" window with sixty QPushButtons and one QLineEdit. How can I make the buttons to add characters into QLineEdit text box? If I press a QPushButton with the label 'Q' on it, I want the program to add the Unicode character 'Q' on the text box.
One way to do this would be to just connect the 'clicked' signal from all the buttons to a slot, and then handle the adding of the character there.
For example, if the all keyboard buttons are inside a layout called 'buttonLayout', in your MainWindow constructor you can do this:
for (int i = 0; i < ui->buttonLayout->count(); ++i)
{
QWidget* widget = ui->buttonLayout->itemAt( i )->widget();
QPushButton* button = qobject_cast<QPushButton*>( widget );
if ( button )
{
connect( button, SIGNAL(clicked()), this, SLOT(keyboardButtonPressed()) );
}
}
Then in the slot implementation, you can use QObject::sender(), which returns the object that sent the signal:
void MainWindow::keyboardButtonPressed()
{
QPushButton* button = qobject_cast<QPushButton*>( sender() );
if ( button )
{
ui->lineEdit->insert( button->text() );
}
}
OPTION 1 - Multiple signals and slots
Connect all pushbuttons clicked() signal to a slot
// Let button01 be the A
connect(ui->button01, SIGNAL(clicked()), this, SLOT(buttonClicked()));
...
// Let button 60 be the Q
connect(ui->button60, SIGNAL(clicked()), this, SLOT(buttonClicked()));
In the buttonClicked() slot you have to figure out which button was clicked and append the corresponding letter to the line edit.
void buttonClicked()
{
QObject* callingButton = QObject::sender();
if (callingButton == button01)
ui->lineEdit->setText(ui->lineEdit->text()+ "A");
...
else if (callingButton == button60)
ui->lineEdit->setText(ui->lineEdit->text()+ "Q");
}
OPTION 2 - Subclass QPushButton
You could subclass QPushButton in order to avoid the multiple ifs. In your subclass just catch the mouse release event and emit a new signal which will contain the button's text
void KeyboardButton::mouseReleaseEvent(QMouseEvent* event)
{
emit clicked(buttonLetter); // Where button letter a variable of every item of your subclass
}
Similarly connect the clicked(QString) signal with a slot
connect(ui->button01, SIGNAL(clicked(QString)), this, SLOT(buttonClicked(QString)));
...
connect(ui->button60, SIGNAL(clicked(QString)), this, SLOT(buttonClicked(QString)));
void buttonClicked(QString t)
{
ui->lineEdit->setText(ui->lineEdit->text()+ t);
}
I have created an application with a similar issue, trying to convert the qpushbutton text to the qlineedit itself. The key is how you initialize the buttons and to use polymorphism in your function. To create an emit signal wont work for individual characters. The .digitValue will work if the case if for numerics (which the buttons would be of type int), but qt doesnt have a character value (I should say after 6hrs of reading qt doc and another 4 of trying different combinations it would not work), I think it has to do with how many bits it takes to store each variable type in an array. I even tried converting the button->text to QString to use with the emit function as a signal prototyped.
I do not know what your button layout is, but I will give you a synopsis of what I did. I first created a global, static const char array containing all the letters needed e.g.
static const char vowelarray[] = "AEIOU";
Then initialized the QPushButtons with in the MainWindow function, using iteration, setting a for loop's terminating condition equal to the size char array (in your case 60?). This all depends on your button layout though. I personally created a void function (setLocation) for the button->setGeometry of each button and iterated the setGeometry, and then passed the function to the MainWindow Function, at end of fucntion. The following code was used to initialize the buttons, connect signals to slots, and use polymorphism to connect to lineedit.
for (int i = 0; i < 26; i++){
characterButton[i] = new QPushButton(chararry[i], this); `
characterButton[i] -> setStyleSheet("QPushButton{background: grey; color: brown}");
connect(characterButton[i],SIGNAL(released(),this,SLOT(characterPushed()));
}
setLocation();
Then created a void function (e.g. void MainWindow::characterPuched()) where the following code was used:
void MainWindow::characterPushed(){
QPushButton *characterButton = (QPushButton*) sender();
if (characterButton )
{
lineEdit -> setText(letters.insert(letters.size(), characterButton -> text()));
}
lineEdit -> setText(letters);
}
of course letters was a global variable as well as:
QString letters = "";
and of course the QPushButtons and the function were prototype in the header file as a private variables and slots, e.g.
private:
QPushButton *characterButton[26];
the variable 'letters' was used to extract and input text to and from the line edit for further functions throughout the application.
Best Luck!!``

Resources