i'm working to creat an interface that dynamically generates QgroupeBox with layouts, i get the number of groupebox needed and it perfectly work. now i want to use a button to destroy these groupBoxes for a repeat section of the same action (get the number of groupeBox needed and creat them)
this is the code i used for this:
void interface::on_pushButton_12_clicked(){
int i,k;
ui->pushButton_13->setEnabled(true);
QGroupBox *first = new QGroupBox(this);
QVBoxLayout *test = new QVBoxLayout;
k = recupEdit();
ui->pushButton_12->hide();
ui->lineEdit->hide();
ui->label->hide();
for(i = 1; i<=k;i++)
{
first = creatgroupebox();
test->addWidget(first);
test->addStretch(1);
ui->tab->setLayout(test);
}
}
int interface::recupEdit(){
int k;
QString recup = ui->lineEdit->text();
k = recup.toInt(0,10);
return k;
}
QGroupBox *interface::creatgroupebox()
{
QGroupBox *group = new QGroupBox(this);
QLineEdit *Id = new QLineEdit("Id");
QLineEdit *Data1 = new QLineEdit("Data 1");
QLineEdit *Data2 = new QLineEdit("Data 2");
QLineEdit *Data3 = new QLineEdit("Data 3");
QLineEdit *Data4 = new QLineEdit("Data 4");
QLineEdit *Data5 = new QLineEdit("Data 5");
QLineEdit *Data6 = new QLineEdit("Data 6");
QLineEdit *Data7 = new QLineEdit("Data 7");
QLineEdit *Data8 = new QLineEdit("Data 8");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(Id);
layout->addWidget(Data1);
layout->addWidget(Data2);
layout->addWidget(Data3);
layout->addWidget(Data4);
layout->addWidget(Data5);
layout->addWidget(Data6);
layout->addWidget(Data7);
layout->addWidget(Data8);
group->setLayout(layout);
return group;
}
void interface::on_pushButton_13_clicked()
{
ui->pushButton_12->show();
ui->lineEdit->show();
ui->label->show();
}
You can get all child objects by using QObject::children()
auto gb = new QGroupBox();
gb->setLayout(new QHBoxLayout());
gb->layout()->addWidget(new QLineEdit());
foreach (QObject *o, gb->layout()->children()) {
auto le = qobject_cast<QLineEdit*>(o);
if (!le)
continue;
//do what you need with your linedit
}
Is it what you want?
Related
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.
Can I add some widgets like QLabel and QPushButton into a QTabWidget?
Actually, I want to do something like this:
I'm using C++ and Qt.
Thanks
It's possible, just use QTabWidget::setCornerWidget.
Quick example:
QWidget* pTabCornerWidget = new QWidget(this);
QLabel* pLabelTime = new QLabel(pTabCornerWidget);
pLabelTime->setText("10:22:20");
QPushButton* pButton = new QPushButton(pTabCornerWidget);
pButton->setText("?");
pButton->setMaximumSize(QSize(25, 25));
QHBoxLayout* pHLayout = new QHBoxLayout(pTabCornerWidget);
pHLayout->addWidget(pLabelTime);
pHLayout->addWidget(pButton);
mUI.tabWidget->setCornerWidget(pTabCornerWidget, Qt::TopRightCorner);
If you want do this stuff, I recommend you use QTabBar instead of QTabWidget. For example, your code can be (remember, that it's just a very simple example):
// Here some first widget
QWidget *wid1 = new QWidget(this);
QHBoxLayout *wid1Lay = new QHBoxLayout(wid1);
wid1Lay->addWidget(new QLabel(tr("Widget1")));
// Here some second widget
QWidget *wid2 = new QWidget(this);
QHBoxLayout *wid2Lay = new QHBoxLayout(wid2);
wid2Lay->addWidget(new QLabel(tr("Widget2")));
// Here some third widget
QWidget *wid3 = new QWidget(this);
QHBoxLayout *wid3Lay = new QHBoxLayout(wid3);
wid3Lay->addWidget(new QLabel(tr("Widget3")));
// Here your Tab bar with only bars
QTabBar *bar = new QTabBar(this);
bar->addTab("One");
bar->addTab("Two");
bar->addTab("Three");
// Here some label (for example, current time) and button
QLabel *lab = new QLabel(tr("Some text"), this);
QPushButton *but = new QPushButton(tr("Push"), this);
// Main layouts
QVBoxLayout *vLay = new QVBoxLayout(ui->centralWidget);
QHBoxLayout *hLay = new QHBoxLayout();
vLay->addLayout(hLay);
hLay->addWidget(bar);
// Spacer for expanding left and right sides
hLay->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
hLay->addWidget(lab);
hLay->addWidget(but);
vLay->addWidget(wid1);
vLay->addWidget(wid2);
vLay->addWidget(wid3);
// Some simple connect with lambda for navigation
connect(bar, &QTabBar::currentChanged, [=] (int index) {
wid1->setVisible(false);
wid2->setVisible(false);
wid3->setVisible(false);
switch(index) {
case 0: wid1->setVisible(true);
break;
case 1: wid2->setVisible(true);
break;
case 2: wid3->setVisible(true);
break;
default:{}
}
});
emit bar->currentChanged(0);
In one of my windows I made a button responsible for creating dynamic array of buttons. After they are made I can't make 'anul' button close the window
Here's the code
QWidget *centralWidget = new QWidget;
int licznik=1;
QString licz;
QString kolumny = ui->lineEdit->text();
QString wiersze = ui->lineEdit_2->text();
QPushButton *button[wiersze.toInt()][kolumny.toInt()];
QGridLayout *controlsLayout = new QGridLayout;
for(int i=0;i<wiersze.toInt();i++)
{
for(int j=0;j<kolumny.toInt();j++)
{
licz = QString::number(licznik);
licznik++;
button[i][j] = new QPushButton(licz);
button[i][j]->setCheckable(1);
controlsLayout->addWidget(button[i][j], i, j);
}
}
QPushButton *okej = new QPushButton("Zatwierdź");
QPushButton *anul = new QPushButton("Anuluj");
if(anul->isDown() == true)
this->close();
controlsLayout->addWidget(okej, wiersze.toInt(), 0);
controlsLayout->addWidget(anul, wiersze.toInt(), 1);
controlsLayout->setHorizontalSpacing(0);
controlsLayout->setVerticalSpacing(0);
centralWidget->setLayout(controlsLayout);
setCentralWidget(centralWidget);
I also tried to change this->close() with centralWidget->close()
This code is executed one time only.
if(anul->isDown() == true)
this->close();
What you want is to connect the clicked() signal of the button to a function (slot)
connect(anul, SIGNAL(clicked()), this,SLOT(close()))
I had a console-game that was written on c++ and since I am currently trying to learn Qt I decided to add GUI to this program as an exercise.
So there's main window named "gui" that inherits Qwidget. It has layout QHBoxLayout* main_h_lo. Which has 2 added layouts: 1. QStackedLayout* leftpart, 2. QGridLayout* deck. The first is some sort of menu-part. It has 4 different widgets with their layouts. For example choosing game mode or printing game score. And second layout - deck - is game table, similar to chessboard.
There's constructor code which I suppose contains the problem:
gui::gui(QWidget *parent) :
QWidget(parent), pgame(nullptr)
{
QHBoxLayout* main_h_lo = new QHBoxLayout;
main_h_lo->setMargin(0);
main_h_lo->setSpacing(0);
setLayout(main_h_lo);
//leftpart-widgets initialization:
bot_or_playerW = new QWidget;
QVBoxLayout* bot_or_playerL = new QVBoxLayout;
bot_or_playerL->addWidget(new QLabel("Choose game mode"));
QPushButton* qpb1 = new QPushButton("vs Human");
QPushButton* qpb2 = new QPushButton("vs Bot");
QObject::connect(qpb1, SIGNAL(clicked()), SLOT(pvp()));
QObject::connect(qpb2, SIGNAL(clicked()), SLOT(pvb()));
bot_or_playerL->addWidget(qpb1);
bot_or_playerL->addWidget(qpb2);
bot_or_playerW->setLayout(bot_or_playerL);
choosing_colourW = new QWidget;
QVBoxLayout* choosing_colourL = new QVBoxLayout;
choosing_colourL->addWidget(new QLabel("Choose your colour"));
QPushButton* qpb3 = new QPushButton("white(2nd turn)");
QPushButton* qpb4 = new QPushButton("black(1st turn)");
QObject::connect(qpb3, SIGNAL(clicked()), SLOT(chwh()));
QObject::connect(qpb4, SIGNAL(clicked()), SLOT(chbl()));
choosing_colourL->addWidget(qpb3);
choosing_colourL->addWidget(qpb4);
choosing_colourW->setLayout(bot_or_playerL);
score_lturnW = new QWidget;
QVBoxLayout* score_lturnL = new QVBoxLayout;
lturn = new QLabel;
pturn = new QLabel;
score = new QLabel;
score_lturnL->addWidget(lturn);
score_lturnL->addWidget(pturn);
score_lturnL->addWidget(score);
score_lturnW->setLayout(score_lturnL);
after_gameW = new QWidget;
QVBoxLayout* after_gameL = new QVBoxLayout;
winner = new QLabel;
offer_to_play_again = new QLabel("Wanna play again?");
QPushButton* qpb5 = new QPushButton("yes");
QObject::connect(qpb5, SIGNAL(clicked()), SLOT(restart()));
QPushButton* qpb6 = new QPushButton("no");
QObject::connect(qpb6, SIGNAL(clicked()), qApp, SLOT(quit()));
after_gameW->setLayout(after_gameL);
leftpart = new QStackedLayout;
leftpart->addWidget(bot_or_playerW);
leftpart->addWidget(choosing_colourW);
leftpart->addWidget(score_lturnW);
leftpart->addWidget(after_gameW);
//"rightpart" init:
deck = new QGridLayout;
deck->setMargin(0);
deck->setSpacing(0);
e_pic = QPixmap("empty.png");
b_pic = QPixmap("black.png");
w_pic = QPixmap("white.png");
pic_sz = e_pic.size();
for (int i = 0; i < 8; ++i)
for (int j = 0; j < 8; ++j)
{
QPushButton* tqpb = new QPushButton;
tqpb->setIcon(e_pic);
tqpb->setIconSize(pic_sz);
std::stringstream ss;
std::string s;
ss << i << j;
ss >> s;
tqpb->setObjectName(s.c_str());
deck->addWidget(tqpb, i, j);
connect(tqpb, SIGNAL(clicked()), SLOT(turn_try()));
}
main_h_lo->addLayout(leftpart);
main_h_lo->addLayout(deck);
leftpart->setCurrentWidget(bot_or_playerW);
}
I get no error or warning. The deck part is scary and ugly but it is as expected :D. The "menu" part does not show up - that is the problem. Screen: http://i.imgur.com/Sh9PU9N.jpg .
Some comments about you code -
A layout can be given the parent on construction and it will automatically become the default layout. This saves you one command, but makes it more implicit. It all depends on what you prefer - implicit or explicit.
Loose the QObject::connect. A simple 'connect' will do.
Are you sure "black(1st turn)" is correct? In a conventional chess game, white generally goes first.
You can avoid std::stringstream and use QString::number instead.
The problem has already been mentioned by 'hyde'.
Say I have a QHBoxLayout where there are 2 QTextEdits and between them a button with an arrow to the right. When you click on the button, the right-side QTextEdit gradually closes by moving the left border until it meets the right one. Simultaneously, the right border of the left QTextEdit takes the place which the right QTextEdit released. And after pressing on the button, the state of the system is coming to the former one.
EDIT: In order to organize this I have done the following:
1) In header file:
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
int m_deltaX;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
2) In the source file:
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1);
m_layout->addWidget(m_pushButton);
m_layout->addWidget(m_textEditor2);
setLayout(m_layout);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "geometry");
QPropertyAnimation *animation2 = new QPropertyAnimation(m_pushButton, "geometry");
QPropertyAnimation *animation3 = new QPropertyAnimation(m_textEditor1, "geometry");
if(isClosing) //close the second textEdit
{
m_pushButton->setText("<");
QRect te2_1 = m_textEditor2->geometry();
m_deltaX = te2_1.width()-3;
QRect te2_2(te2_1.x()+m_deltaX, te2_1.y(), 3 ,te2_1.height());
QRect pb_1 = m_pushButton->geometry();
QRect pb_2(pb_1.x()+m_deltaX, pb_1.y(), pb_1.width() ,pb_1.height());
QRect te1_1 = m_textEditor1->geometry();
QRect te1_2(te1_1.x(), te1_1.y(), te1_1.width()+m_deltaX, te1_1.height());
//animation->setDuration(10000);
animation1->setStartValue(te2_1);
animation1->setEndValue(te2_2);
animation2->setStartValue(pb_1);
animation2->setEndValue(pb_2);
animation3->setStartValue(te1_1);
animation3->setEndValue(te1_2);
}
else //open
{
m_pushButton->setText(">");
QRect te2_1 = m_textEditor2->geometry();
QRect te2_2(te2_1.x()-m_deltaX, te2_1.y(), 3+m_deltaX ,te2_1.height());
QRect pb_1 = m_pushButton->geometry();
QRect pb_2(pb_1.x()-m_deltaX, pb_1.y(), pb_1.width() ,pb_1.height());
QRect te1_1 = m_textEditor1->geometry();
QRect te1_2(te1_1.x(), te1_1.y(), te1_1.width()-m_deltaX, te1_1.height());
//animation->setDuration(10000);
animation1->setStartValue(te2_1);
animation1->setEndValue(te2_2);
animation2->setStartValue(pb_1);
animation2->setEndValue(pb_2);
animation3->setStartValue(te1_1);
animation3->setEndValue(te1_2);
}
animation1->start();
animation2->start();
animation3->start();
}
EDIT:
And I have the following problem:
When I close the second QTextEdit (by clicking on the button) and resize the MyWidget, then the QTextEdit restores its state (but it should stay closed of course). How can I solve this problem?
Please provide me with a code snippet.
Qt's Animation framework sounds like a good place to start. You could just try to follow their tutorials, adapting for you use case. I have used it already, and it seemed quite straight forward.
1) You could replace your button with a vertical layout, place the button inside this layout and finally add a vertical spacer below the button (in same the layout).
...
QVBoxLayout* m_buttonLayout = new QVBoxLayout();
m_layout = new QHBoxLayout();
m_layout->addWidget(m_textEditor1);
m_layout->addLayout(m_buttonLayout);
m_layout->addWidget(m_textEditor2);
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
2) I guess you could (and should) animate widget's maximumSize (or just maximumWidth) property and let the layout take care of calculating actual geometries. This would also simplify your calculations. E.g.
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
QPropertyAnimation *animation2 = new QPropertyAnimation(m_textEditor, "maximumWidth");
if (isClosing)
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = 0;
int textEdit_start = m_textEditor->maximumWidth();
int textEdit_end = textEdit_start + textEdit2_start;
animation1->setStartValue(textEdit2_start);
...
}
Also, now you don't have to animate buttons geometry at all (assuming that you have set fixed size to it).
PS. I didn't compile codes so there might be minor errors but you should get the idea.
Here what I wanted:
Header file
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
QVBoxLayout *m_buttonLayout;
int m_deltaX;
bool m_isClosed;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
void resizeEvent( QResizeEvent * event );
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
Source file
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
m_pushButton->setFixedSize(16,16);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_buttonLayout = new QVBoxLayout();
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1, 10);
m_layout->addSpacing(15);
m_layout->addLayout(m_buttonLayout);
m_layout->setSpacing(0);
m_layout->addWidget(m_textEditor2, 4);
setLayout(m_layout);
resize(800,500);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
m_isClosed = isClosing;
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
if(isClosing) //close the second textEdit
{
m_textEditor2->setMaximumWidth(m_textEditor2->width());
int textEdit2_start = m_textEditor2->maximumWidth();
m_deltaX = textEdit2_start;
int textEdit2_end = 3;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText("<");
}
else //open
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = m_deltaX;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText(">");
}
animation1->start();
}
void MyWidget::resizeEvent( QResizeEvent * event )
{
if(!m_isClosed)
m_textEditor2->setMaximumWidth( QWIDGETSIZE_MAX );
}