I have
QWidget *myWidget; //on my mainWindow with Qt Creator
and a
QComboBox *myComboBox;
When I change my selection of myComboBox, I would like to delete
myWidget->layout();
and set to myWidget another layout.
I'm doing : (with this help : https://stackoverflow.com/a/12034868/6105710)
void ConfWindow::on_comboBouton_currentIndexChanged(const QString &arg1)
{
if(ui->myWidget->layout()){
auto myLayout = ui->myWidget->layout();
QLayoutItem *item;
while((item = myLayout->takeAt(0)) != 0){
myLayout->removeItem(item);
delete item;
}
delete myLayout;
}
for(int i=0; i< someVector->size(); i++){
if( someVector->at(i)->getName() == arg1){
ui->myWidget->setLayout( someVector->at(i)->getLayout()); //which return a QHBoxLayout.
break;
}
}
}
and when I change my comboBox, It is painting my new layout, but my old layout still here..
I tried repaint(), update() etc...
Is it because I create layout in another class and add it with
auto myVector = new QVector<myClass>;
setLayout( myVector->getLayout() )
? I don't think so because I'm using pointer .. I don't understand ...
Related
I have a class StackedWidget which inherits from QStackedWidget. The standard behaviour of QStackedWidget is that it adopts the size of its biggest element. What I want to do is force it to resize to its current element. I have already tried a couple of solutions found here and none of them work including e.g. setting size policies or calling hide() on all the widgets that go out of sight.
I think problem may reside in two possibilities:
1. Something is terribly wrong with StackedWidget. 2. The problem of resizing does not pertain directly to StackedWidget but to some layout or another widget that StackedWidget is nested in.
Concerning the first possibility, here I provide the StackedWidget class.
Please take a look at what my StackedWidget's declaration looks like:
class StackedWidget : public QStackedWidget
{
Q_OBJECT
private:
QComboBox* widgetChooser = nullptr;
public:
StackedWidget(QWidget* parent) : QStackedWidget(parent) {}
void setWidgetChooser(QComboBox* widgetChooser);
void addWidget(QWidget* widget);
private:
void makeConnection();
signals:
public slots:
void setCurrentIndex(const int& index);
};
Here goes the definition:
void StackedWidget::setWidgetChooser(QComboBox* widgetChooser)
{
if (widgetChooser == nullptr) throw RuntimeError("widgetChooser is nullptr");
this->widgetChooser = widgetChooser;
makeConnection();
}
void StackedWidget::addWidget(QWidget* widget)
{
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QStackedWidget::addWidget(widget);
}
void StackedWidget::makeConnection()
{
connect(widgetChooser, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentIndex(int)));
}
void StackedWidget::setCurrentIndex(const int& index)
{
qDebug() << "Index changed to " << index;
QWidget* pWidget = widget(index);
Q_ASSERT(pWidget);
QStackedWidget::setCurrentWidget(pWidget);
pWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pWidget->adjustSize();
adjustSize();
}
Concering the second possibility, here goes how I use StackedWidget.
void SchemaWidget::TempBuildAlt(const SchemaElement* son, QVBoxLayout* parentLayout)
{
if (auto schemaAlternative = dynamic_cast<const SchemaAlternatives*>(son))
{
QComboBox* widgetBox = BuildWidgetChooserBox(schemaAlternative);
StackedWidget* stackedWidget = BuildStackedWidget(schemaAlternative);
stackedWidget->setWidgetChooser(widgetBox);
QHBoxLayout* boxLayout = new QHBoxLayout;
boxLayout->addWidget(new QLabel(schemaAlternative->Name, this));
boxLayout->addWidget(widgetBox);
QVBoxLayout* layout = new QVBoxLayout;
layout->addLayout(boxLayout);
layout->addWidget(stackedWidget);
parentLayout->addLayout(layout);
} else throw RuntimeError("Cannot cast son to SchemaAlternatives.");
}
QComboBox* SchemaWidget::BuildWidgetChooserBox(const SchemaAlternatives* schema)
{
QComboBox* alternativesBox = new QComboBox(this);
QStringListModel* listModel = new QStringListModel(this);
QStringList list;
for (int i = 1; i <= schema->Sons.High(); ++i)
{
if (const SchemaTree* son = dynamic_cast<const SchemaTree*>(schema->Sons(i).Get()))
{
list << son->Name;
}
else throw RuntimeError("Son cannot be cast to SchemaTree.");
}
listModel->setStringList(list);
alternativesBox->setModel(listModel);
return alternativesBox;
}
StackedWidget* SchemaWidget::BuildStackedWidget(const SchemaAlternatives* schema)
{
StackedWidget* stackedWidget = new StackedWidget(this);
for (int i = 1; i <= schema->Sons.High(); ++i)
{
if (const SchemaTree* alternativeSon = dynamic_cast<const SchemaTree*>(schema->Sons(i).Get()))
{
QWidget* widget = new QWidget(this);
QVBoxLayout* widgetLayout = new QVBoxLayout;
BuildWidget(alternativeSon, widgetLayout);
widget->setLayout(widgetLayout);
stackedWidget->addWidget(widget);
}
else throw RuntimeError("Son could not be cast to SchemaTree.");
}
return stackedWidget;
}
I want to say thanks in advance to anyone who will be willing to spend some time on my problem. I do appreciate it. Thanks. You're great.
I have a little problem displaying my layouts. I have an application that contains a GridLayout, HBoxLayout, and VBoxLayout.
The HBoxLayout contains: a button and line edit
The GridLayout contains: progbars (1-99)
The HBoxLayout and the GridLayout are put in a VBoxLayout
My problem is when I click, The grid layout appears on the HBoxLayout. It's like the HBoxLayout wasn't a part of the VBoxLayout. So, even when I destroy the layout and create it again, I still have the same problem.
An image is displayed below to better understand my problem.
code: window.cpp
Window::Window(QWidget *parent) :
QWidget(parent){
label = NULL;
progressbar = NULL;
workerThread = NULL;
m_counter = NULL;
layout = new QHBoxLayout(NULL);
lineEdit = new QLineEdit(NULL);
m_button = new QPushButton("click", NULL);
time= new QTimer(this);
lineEdit-> setInputMask("00");;
//lineEdit->setGeometry(400,10,160,30);
lineEdit->setPlaceholderText("N between 1 & 99");
// Create and position the button
// m_button->setGeometry(100, 10, 150, 30);
QIcon icon("/home/ca/Downloads/chauvin.png");
m_button->setIcon(icon);
m_button->setIconSize(QSize(100, 30));
m_button->setToolTip("this is a beautifull button ");
//layout = new QFormLayout;
layout->addWidget(m_button);
layout->addWidget(lineEdit);
setLayout( layout );
// showTime();
time->start(1000);
setWindowTitle(tr("Digital Clock"));
// NEW : Do the connection
connect(m_button, &QPushButton::pressed, this , &Window::slotButtonPressed);}
void Window::slotButtonPressed(){
layoutgrid = new QGridLayout(NULL);
m_button->setEnabled(true);
QString contenu = lineEdit->text();
int i_contenunumber= contenu.toInt(0,10);
m_counter= new int[i_contenunumber];
memset( m_counter, 0, i_contenunumber );
label = new QLabel*[ i_contenunumber ];
progressbar = new QProgressBar*[ i_contenunumber ];
workerThread= new mythread*[ i_contenunumber ];
int x= 0;
int y= -1;
int i=0;
m_button->setText("Checked");
for(i=0;i< i_contenunumber ;i++)
{
if (i%5==0)
{
x=0;
y++;
}
int i_Randomvalue = rand() % 500 + 100;
// label[i] = new QLabel(NULL);
// //label[i]->setGeometry(100*x*1.7, 80+(50*y), 160, 30);
// label[i]->setText("Tread" + QString::number(i_Randomvalue));
// label[i]->setVisible(true);
progressbar[i] = new QProgressBar(NULL);
progressbar[i]->setRange(0, 100);
progressbar[i]->setOrientation(Qt::Horizontal);
//progressbar[i]->setGeometry(100*x*1.7,60+(50*y),150,30);
progressbar[i]->setValue(0);
progressbar[i]->setVisible(true);
layoutgrid->addWidget(progressbar[i],y,x);
setLayout(layoutgrid);
workerThread[i] = new mythread(i_Randomvalue, i);
connect(workerThread[i], &mythread::signalemit, this, &Window::barprogress);enter code here
connect(workerThread[i], &mythread::signalFinThread, this, &Window::findethread);
workerThread[i] ->start();
x++;
m_counter[i]=0;
}
// Window::setFixedSize(1000,120+(50*y-1));
removeLayout();
layoutvbox = new QVBoxLayout(NULL);
layoutvbox->addLayout(layout);
layoutvbox->addLayout(layoutgrid);
setLayout(layoutvbox);
adjustSize();
}
void Window::removeLayout ( void )
{
QLayout* po_l_layout = QWidget::layout ();
if (po_l_layout != 0)
{
QLayoutItem *item;
while ((item = po_l_layout->takeAt(0)) != 0)
po_l_layout->removeItem (item);
delete po_l_layout;
}
}
delete layout will not work here because it will not delete all the containing widgets
Instead just create a new widget that contains the layout
m_widget = new QWidget();
QGridLayout *outerLayout = new QGridLayout(m_widget);
m_layout->addWidget(m_widget);
this->setLayout(m_layout);
to remove and rebuild just delete the widget
delete m_widget
deleting a widget deletes all sub layouts and widgets contained by the widget
Once the layout of your widget is set, you can not change it unless you remove the old layout. My suggestion is to delete the old layout
//remove all of layouts widgets here
delete layout
Then create the QVBoxLayout and call setLayout(layoutvbox)
If you wish to switch back and forth, just recreate/delete when needed.
I would like to get a number of a QTableWidget row after selecting some topic in comboBox how it is possible to get the row, thanks.
void MainWindow::metto_stringa(int i)
{
QWidget *w = qobject_cast<QWidget *>(sender()->parent());
if(w)
{
int row = ui->tableWidget->indexAt(w->pos()).row();
ui->lineEdit->setText(QString::number( row ));
}
// ui->lineEdit->setText(QString::number( i ));
}
else if(i == 3)
{
// ui->tableWidget->setCellWidget(ui->tableWidget->rowCount(), i, "");
QString s = "Normal";
QComboBox *combo = new QComboBox;
combo->addItem("Below normal");
combo->addItem("Normal");
combo->addItem("Above normal");
combo->addItem("High");
combo->addItem("Real time");
connect(combo,SIGNAL(currentIndexChanged(int)),this,
SLOT(metto_stringa(int)));
ui->tableWidget->setCellWidget(ui->tableWidget->rowCount()-1, i,combo);
/* ui->tableWidget->setCellWidget(i,4,combo);
QTableWidgetItem*item = new QTableWidgetItem(s);
item->setFlags(item->flags() ^ Qt::ItemIsEditable);
ui->tableWidget->setItem(ui->tableWidget->rowCount()-1, i,
item);*/
continue;
}
In this case you should not use the parent of the QComboBox, you must use the same sender()
void MainWindow::metto_stringa(int index)
{
QWidget *w = qobject_cast<QWidget *>(sender());
if(w)
{
int row = ui->tableWidget->indexAt(w->pos()).row();
ui->lineEdit->setText(QString::number(row));
}
}
In the question I answered before I commented that you must access the widget that you use in the setCellWidget() function, in the previous case the widget had the following form:
QWidget <--- QPushButton
parent() sender()
ie you owe to that widget so we take advantage of sender() and parent() in the previous case. In the current case QComboBox is added directly.
I'm pretty new to c++ and qt. I'm not sure if i use the right terminology describe what I want to achieve. But here it goes.
My application spawns and removes widgets in a gridlayout when the user pushes buttons. Managed to do this successfully. However when the user uses the spawned widgets I want the widgets to interact with each other.
QList<QLineEdit*> m_ptrLEPathList;
QList<QPushButton*> m_ptrPBList;
qint8 m_noFields;
void MainWindow::on_pbIncFields_clicked()
{
//create widgets and place on a new row in a gridLayout
QLineEdit *lineEditPath = new QLineEdit(this);
QPushButton *pushButton = new QPushButton(this);
//storing pointers in lists to be able to delete them later.
m_ptrLEPathList.append(lineEditPath);
m_ptrPBList.append(pushButton);
ui->gridLayout->addWidget(m_ptrLEPathList.last(),m_noFields,0);
ui->gridLayout->addWidget(m_ptrPBList.last(),m_noFields,1);
connect(m_ptrPBList.last(), SIGNAL(clicked(bool), this, SLOT(on_addPath()));
m_noFields++;
}
void MainWindow::on_pbDecFields()
{
//delete last spawned widgets
}
void MainWindow::on_addPath()
{
QFileDialog getPath();
getPath.exec();
//somehow set the text of the line edit spawned on the same row as the pushbutton
}
So my slot is executed when I push any spawned button but I have no idea how to store the data from the file dialog in the related lineEdit.
Is the basic idea of what I'm trying to do ok or is there any other solution to achieve the fuctionality I'm looking for?
In on_addPath slot you can use QObject::sender method to get the clicked button, and, assuming m_ptrLEPathList and m_ptrPBList lists are equal, you can easily get the corresponding QLineEdit:
void MainWindow::on_addPath()
{
QFileDialog dialog;
if (!dialog.exec())
{
return;
}
QStringList fileNames = dialog.selectedFiles();
if (fileNames.isEmpty())
{
return;
}
QPushButton *btn = qobject_cast<QPushButton*>(sender());
if (!btn)
{
return;
}
Q_ASSERT(m_ptrPBList.size() == m_ptrLEPathList.size());
int index = m_ptrPBList.indexOf(btn);
if (index == -1)
{
return;
}
QLineEdit *edit = m_ptrLEPathList.at(index);
edit->setText(fileNames.first());
}
You are including 'on_addPath' function out of the scope of the 'MainWindow' class, so when the slot is called you have not access to member elements in the class.
Try to include the slot function into the class and check if you have direct access to the member elements. Also, the 'lineEditPath' element must be a member object, so it must be included into the class definition.
Something like this:
void MainWindow::on_addPath()
{
QFileDialog getPath();
getPath.exec();
QStringList fileNames = dialog.selectedFiles();
if (fileNames.isEmpty())
{
return;
}
m_lineEditPath->setText(fileNames.first());
}
First off, void on_addPath() must be void MainWindow::on_addPath()
As for linking the data from QFileDialog it is simple. Try this:
void MainWindow::on_addPath() {
/* Get the push button you clicked */
QPushButon *btn = qobject_cast<QPushButton*>( sender() );
/* Make sure both the lists have the same size */
Q_ASSERT(m_ptrPBList.size() == m_ptrLEPathList.size());
/* If the sender is a button in your list */
if ( m_ptrPBList.contains( btn ) ) {
/* Get the index of your push button */
int idx = m_ptrPBList.indexOf( btn );
/* Get the corresponding line edit */
QLineEdit *le = m_ptrLEPathList.at( idx );
/* Get your path */
QString path = QFileDialog::getOpenFileName( this, "Caption", "Default Location" );
/* If you path is not empty, store it */
if ( not path.isEmpty() )
le->setText( path );
}
}
Add a map to private section
QMap<QPushButton*, QLineEdit*> map;
Then
QLineEdit *lineEditPath = new QLineEdit(this);
QPushButton *pushButton = new QPushButton(this);
map.insert(pushButton, lineEditPath);
You can use sender() method like follow:
void on_addPath()
{
QFileDialog getPath();
getPath.exec();
QObject* obj = sender();
QPushButton *pb = 0;
if((pb = qobject_cast<QPushButton *>(obj)) != 0) {
QLineEdit* lineEdit = map->value(pb, 0);
if( lineEdit != 0 )
lineEdit->setText( getPath.<some function to get selected file name> );
}
}
I think the cleanest solution would be to contain the QLineEdit and QPushButton in a custom widget class, if it suits your project. That way you could use the file dialog inside this class, and you won't have to store the widgets in lists. It is hard to give you all the information, as you didn't really provide any details what your application is supposed to do. But in any case, the custom widget class would look something like this (you should define all the functions inside a .cpp file):
#ifndef WIDGETCONTAINER_H
#define WIDGETCONTAINER_H
#include <QWidget>
#include <QLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QFileDialog>
class WidgetContainer : public QWidget
{
Q_OBJECT
public:
WidgetContainer(QWidget *parent = 0) : QWidget(parent)
{
setLayout(new QHBoxLayout);
button.setText("BUTTON");
layout()->addWidget(&lineEdit);
layout()->addWidget(&button);
connect(&button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
}
private:
QLineEdit lineEdit;
QPushButton button;
private slots:
void buttonPressed()
{
QString filename = QFileDialog::getSaveFileName();
lineEdit.setText(filename);
}
};
#endif // WIDGETCONTAINER_H
I am trying to use a Turkish translation file for my Qt project. I used Qt Linguist for generating the .ts file. The problem is when I load the translation file in my application, I am getting segmentation faults whenever I click on any item of QMenuBar.
I also have a context menu that is triggered with the contextMenuEvent of a GraphicsView in mainwindow. The program gives a segmentation fault when I try to execute the below line.
mContextMenu->exec(event->globalPos());
mContextMenu is a QMenu* and exec returns a QAction*. Basically I guess that when the translation belongs to a QAction this problem occurs. I saw the same problem when I translate the toolTips of toolButtons. How should I handle the translation of QActions and toolTips?
I am adding some actions to mContextMenu as below:
void RadarView::prepareMainMenu() {
mContextMenu = new QMenu();
//showLineAction->setShortcut(QKeySequence("Alt+Shift+L"));
mpStartRulerAction = new QAction(QObject::tr("Start Ruler"), this);
mContextMenu->addAction(mpStartRulerAction);
connect(mpStartRulerAction, SIGNAL(triggered()), this,
SLOT(menuStartRulerClicked()));
mpStartRulerAction->setProperty("TYPEVIEW", MV_StartRuler);
mpEndRulerAction = new QAction(QObject::tr("End Ruler"), this);
mContextMenu->addAction(mpEndRulerAction);
connect(mpEndRulerAction, SIGNAL(triggered()), this, SLOT(menuEndRulerClicked()));
mpEndRulerAction->setProperty("TYPEVIEW", MV_EndRuler);
mpCriticalRegionAction = new QAction(QObject::tr("Critical Region"), this);
mContextMenu->addAction(mpCriticalRegionAction);
connect(mpCriticalRegionAction, SIGNAL(triggered()), this, SLOT(menuDefineCriticalRegionClicked()));
mpCriticalRegionAction->setProperty("TYPEVIEW", MV_Critical_Region);
mpAScopeAction = new QAction(QObject::tr("A-Scope Line"), this);
mContextMenu->addAction(mpAScopeAction);
connect(mpAScopeAction, SIGNAL(triggered()), this, SLOT(menuAddAScopeLine()));
mpAScopeAction->setProperty("TYPEVIEW", MV_A_Scope);
}
Context Menu event of graphics view is implemented as below:
void RadarView::contextMenuEvent(QContextMenuEvent * event) {
LOGGER_START
//check if the item has its own context menu...
QList<QGraphicsItem*> items = this->items(event->pos());
if (items.size() != 0) {
bool isValid = true;
for (int i = 0; i < items.size(); ++i) {
QGraphicsRulerLineItem *rulerLineItem = NULL;
rulerLineItem = dynamic_cast<QGraphicsRulerLineItem*> (items[i]);
if (rulerLineItem != NULL || dynamic_cast<AScopeLineItem*> (items[i]) || dynamic_cast<PpiTargetItem*> (items[i])){
isValid = false;
}
else {
PpiPlotItem *targetItem = NULL;
targetItem = dynamic_cast<PpiPlotItem*> (items[i]);
if (targetItem != NULL) {
isValid = false;
if (currentVisibleMenuItems.contains(0)) {
startItem = targetItem;
} else if (currentVisibleMenuItems.contains(1)) {
endItem = targetItem;
}
}
}
}
if (isValid == true) {
if(currentVisibleMenuItems.size() ==0)
return;
//Get last clicked Position.
mLastClickedPos = event->pos();
//show menu of RadarView...
mpRightClickAction = mContextMenu->exec(event->globalPos());
} else {
QGraphicsView::contextMenuEvent(event);
}
}
LOGGER_END
}
The problem I described above is solved when I used QApplication instead of a customized class that inherits QApplication. Inside of the customized class, bool QApplication::notify ( QObject * receiver, QEvent * e ) function was implemented. When I used QApplication directly, all translations were loaded correctly and no problems ocuured regarding the QAction items and toolTips.