I'm newbie with QT and have read many topics, but I just don't get it. I hope that someone could help me with this.
So, I have created a loop where i add QTables in QGroupBoxes. Table's 2nd column is meant for QCheckBoxes and first column is meant for condition text, which changes when checkbox is ticked.
Everything is working except the text won't change. So problem should be in the signal. I just can't figure it out :(
I would be glad for any help :)
inputBox = new QGroupBox();
QScrollArea *boxScroll = new QScrollArea();
QHBoxLayout *boxLayout = new QHBoxLayout();
boxTable = new QTableWidget();
inputBox->setLayout(boxLayout);
boxLayout->addWidget(boxTable);
boxTable->verticalHeader()->setVisible(false);
boxTable->setRowCount(24);
boxTable->setColumnCount(5);
boxTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
boxTable->setHorizontalHeaderItem(0, new QTableWidgetItem("ID"));
boxTable->setHorizontalHeaderItem(1, new QTableWidgetItem("State"));
boxTable->setHorizontalHeaderItem(2, new QTableWidgetItem("Enable"));
for (int i=0; i<24; i++)
{
inCheck = new QCheckBox();
iCheckLabel = new QLabel();
QTableWidgetItem *id = new QTableWidgetItem();
QTableWidgetItem *state = new QTableWidgetItem();
QTableWidget *checkWidget = new QTableWidget();
QHBoxLayout *checkLayout = new QHBoxLayout();
checkLayout->setAlignment(Qt::AlignCenter);
checkLayout->setContentsMargins(0,0,0,0);
checkLayout->addWidget(inCheck);
checkWidget->setLayout(checkLayout);
id->setText(QString::number(i));
id->setTextAlignment(Qt::AlignCenter);
id->setFlags(id->flags() & ~Qt::ItemIsEditable);
state->setText("Off");
state->setTextAlignment(Qt::AlignCenter);
state->setFlags(state->flags() & ~Qt::ItemIsEditable);
state->setTextColor(Qt::red);
boxTable->setItem(i, 0, id);
boxTable->setItem(i, 1, state);
boxTable->setCellWidget(i, 2, checkWidget);
connect(checkWidget, SIGNAL(cellChanged(int,int)), this, SIGNAL(inCheckChecked(int, int)));
}
inputBox->setMinimumSize(350, 450);
inputBox->setTitle(title);
ui->scrollAreaWidgetContents->layout()->addWidget(inputBox);
void Project::inCheckChecked(int row, int col)
{
QTableWidgetItem *item = boxTable->item(row, col);
if (item->checkState() == true)
{
qDebug("is checked");
}
}
You do something very strange here. You set a layout to your table widget and then add a check box to that layout, then you add this table widget to another table widget. Why? You could just use QTableWidget::setItem(int row, int column, QTableWidgetItem * item) to add a check box, like you use it for id and state items. Just make it a checkable item.
for (int i=0; i<24; i++)
{
QTableWidgetItem *id = new QTableWidgetItem();
QTableWidgetItem *state = new QTableWidgetItem();
QTableWidgetItem *checkItem = new QTableWidgetItem();
...
checkItem->setCheckState(Qt::Unchecked); // shuold be enough to make it checkable..
//you can also set the needed flags
boxTable->setItem(i, 0, id);
boxTable->setItem(i, 1, state);
boxTable->setItem(i, 2, checkItem);
}
Then you just connect the signal from boxTable to your slot, which will notify you when the checkbox state is changed.
In this code, there is bug in below line
connect(checkWidget, SIGNAL(cellChanged(int,int)), this, SIGNAL(inCheckChecked(int, int)));
For using connect, according to your implementation, you want to connect one signal and one slot, that consumes that signal. It should be as below :
connect(checkWidget, SIGNAL(cellChanged(int,int)), this, SLOT(inCheckChecked(int, int)));
Get More info on Signals and Slots here
Related
I have two different views to display inside a QWidget window. Each view has a separate QGraphicsScene.
I want to toggle between the two views on button click.
This is my current implementation:
void toggleUi(bool type){
QGraphicsView* currentView;
if(bool){
currentView = getFirstView(); // returns QGraphicsView of first type
}
else{
currentView = getSecondView(); // returns QGraphicsView of second type
}
QLayout* layout = widget->layout ();
if (layout != 0)
{
QLayoutItem *item;
while ((item = layout->takeAt(0)) != 0)
layout->removeItem (item);
delete layout;
}
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(currentView);
}
Issue: Both views are displayed over one another on toggle, even after deleting the layout and adding a new one.
Both views are rendered fine without toggle.
Is there a better/another way to do it?
Use QStackedWidget! Use the addWidget function to add widgets:
QStackedWidget *stackedWidget = new QStackedWidget(this);
stackedWidget->addWidget(getFirstView());
stackedWidget->addWidget(getSecoundView());
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(stackedWidget);
setLayout(layout);
Here's how to switch between the widgets:
void toggleUi(bool type){
if(condition)
stackedWidget->setCurrentindex(0)
else
stackedWidget->setCurrentindex(1)
I hope it helps!
I know this has been asked several times in different posts, however I am still not convinced that my implementation is the best solution.
I have a QVBoxLayout in which I add a QHBoxLayout which hold widgets. The QVBoxLayout by default is empty.
I delete all layouts widgets using this code, however the widgets can fire signals. Is this save? Also I would rather want to change it to a recursive function as shown in https://stackoverflow.com/questions/4272196/qt-remove-all-widgets-from-layout/7077340#=
QLayoutItem *child;
while ((child = ui->verticalLayoutAmplitude->takeAt(0)) != 0) {
QLayoutItem * subchild;
while ((subchild = child->layout()->takeAt(0)) != 0) {
delete subchild->widget();
delete subchild;
}
delete child->widget();
delete child;
}
What I do not understand is why it is so complicated.
Also the creation of the widgets could be different
The parent layout can not be used in the creation of the widgets.
Thus only the MainWindow as a parent class was inserted.
I wonder what else should be inserted as a parent class?
for (int i = 0; i < parameterList.size(); ++i) {
QString valueName = parameterList.at(i);
double value = parameter(valueName);
QHBoxLayout * hLayout = new QHBoxLayout(this);
QDoubleSpinBox * spinbox = new QDoubleSpinBox();
QLabel * label = new QLabel();
label->setText(valueName);
spinbox->setValue(value);
hLayout->addWidget(label, 1);
hLayout->addWidget(spinbox, 3);
ui->verticalLayoutAmplitude->addLayout(hLayout);
}
I want to dynamically create X labels on a layout. The X is taken from the QSpinBox.
When X is decreased, I need to first remove items on layout and then create a new one, with decreased number of labels:
void dial::quantity1SpinClicked(int val)
{
QLayout *layout = fqbox->layout();
if(layout != 0)
{
QLayoutItem *item;
while ((item = layout->takeAt(0)) != 0)
layout->removeItem (item);
delete layout;
}
QGridLayout *gridLayout = new QGridLayout;
QList<QLabel*> labels;
for (int i = 0; i < val; ++i){
labels << new QLabel(QObject::tr("nr %1").arg(i));
gridLayout->addWidget(labels.at(i), i, 0);
}
fqbox->setLayout(gridLayout);
}
However, my code does not remove items, it creates a new layout, on top on the old one (it looks like so):
How to solve this?
It is needed to delete QLabel widget:
QLayoutItem *item;
while ((item = layout->takeAt(0)) != 0) {
layout->removeItem (item);
delete item->widget();
delete item;
}
Note also description of QLayout::removeItem(QLayoutItem * item):
It is the caller's responsibility to delete the item.
Notice that item can be a layout (since QLayout inherits
QLayoutItem).
I am trying to add widgets dynamically with Qt.
My code looks like this
void MainWindow::on_actionLoad_DAS_Measurement_triggered()
{
QWidget *MeasurementsWidget = new QWidget; //Create a new widget which will show a small icon of the loaded measurements.
QGridLayout *MeasurementLayout = new QGridLayout; //Create a GridLayout which will contain the small icons.
QTextBrowser *Measurements[12] = {new QTextBrowser}; //Create an array for the loaded measurements. This will contain the actual icons respectively.
int MeasurementCount, MeasurementColumns, MeasurementLines, Number;
QStringList LoadDASMeasurement = QFileDialog::getOpenFileNames(this,"","","DAS Measurement (*.dl3; *.dl2)"); //Opening measurements in .dl2 and .dl3 format
MeasurementCount = LoadDASMeasurement.count(); //Saving the number of the loaded measurement
MeasurementCount++; //Increasing the number of the loaded measurement, to create enough columns after the division
MeasurementLines = 2; // 2 lines are used. Can be modified in the future
MeasurementColumns = MeasurementCount / MeasurementLines;
Number = 0;
for (int LineCount = 0; LineCount < MeasurementLines; LineCount++)
{
for (int ColumnCount = 0; ColumnCount < MeasurementColumns; ColumnCount++)
{
MeasurementLayout->addWidget(Measurements[Number],LineCount,ColumnCount);
Number++;
}
}
MeasurementsWidget->setLayout(MeasurementLayout); //Assign the widget to the GridLayout
setCentralWidget(MeasurementsWidget); //Set the Widget as a centralwidget, so it will be shown in the mainwindow
}
I always get a warning message:
QLayout: Cannot add a null widget to QGridLayout/
And only the first widget is shown.
Can anybody help why this warning occurs?
Here's your problem:
QTextBrowser *Measurements[12] = {new QTextBrowser};
That creates an array of 12 pointers where the first is a new QTextBrowser and the rest are all nullptr. You'll need to loop over the array and instantiate 12 individual QTextBrowsers.
I have so when a person clicks a button it should duplicate a tab but I have run into the problem that tab->layout() only returns QLayout and I can't convert it QHBoxLayout.
void MainWindow::on_dublicateSection_clicked()
{
QWidget* tab = tabWidget->currentWidget();
QWidget* newTab = new QWidget(tab);
QHBoxLayout* layout = new QHBoxLayout(tab->layout());
newTab->setLayout(layout);
content->IncreaseArraySize(Section(tabWidget->count()));
QString tabText = tabWidget->tabText(tabWidget->currentIndex());
content->sections[tabWidget->count()].name = tabText;
tabWidget->addTab(newTab,tabText);
}
Actually you can.
QHBoxLayout* hbLayout = qobject_cast<QHBoxLayout*>(tab->layout());
Q_ASSERT(hbLayout);
But keep in mind that QObject derived classes are NOT copyable.