I have setup my QTreeWidget such that each cell is filled with comboboxes, however I would like to create a text edit widget next to the selected combobox (or overwrite the existing combobox), depending on which combobox item the user has selected.
I figured I could do this by adding the comboboxes parent as a property when its initially setup and then upon interaction with the combobox simply use setItemWidget to put a text edit Item in column after the selected combobox (using the same child). But it seems as though the parent is not being passed correctly or some other issue is causing the text edit widget to appear in the row below where it should be.
I've attached a photo and some code for clarification.
This is where I setup the comboboxes for the QTreeWidget (Specifically where rowType == 0)
void customMethodConstructorWindow::addChildRow(QTreeWidget *widgetParent,QTreeWidgetItem *itemParent,int rowType)
{
//widgetParent->setColumnCount(methodBlocks.at(rowType).size());
if(rowType == 0)
{
QTreeWidgetItem *childItem = new QTreeWidgetItem(itemParent);
QVariant itemParentVariant;
itemParentVariant.setValue(itemParent);
for(uint cycleSetup = 0;cycleSetup < methodBlocks.at(rowType).size();cycleSetup++)
{
QComboBox *itemComboBox = new QComboBox;
itemComboBox->setProperty("rowType", rowType);
itemComboBox->setProperty("row", 0);
itemComboBox->setProperty("column",cycleSetup);
itemComboBox->setProperty("itemParent",itemParentVariant);
itemComboBox->addItems(methodBlocks.at(0).at(cycleSetup));
QObject::connect(itemComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnComboIndexChanged(const QString&)));
widgetParent->setItemWidget(childItem,cycleSetup,itemComboBox);
itemParent->addChild(childItem);
}
}
else
{
QTreeWidgetItem *childItem = new QTreeWidgetItem(itemParent);
QComboBox *item0ComboBox = new QComboBox;
item0ComboBox->setProperty("rowType", rowType);
item0ComboBox->setProperty("row", 1);
item0ComboBox->setProperty("column", 0);
item0ComboBox->addItems(methodBlocks.at(1).at(0));
QObject::connect(item0ComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnComboIndexChanged(const QString&)));
widgetParent->setItemWidget(childItem,0,item0ComboBox);
itemParent->addChild(childItem);
QComboBox *item1ComboBox = new QComboBox;
item1ComboBox->setProperty("rowType", rowType);
item1ComboBox->setProperty("row", 1);
item1ComboBox->setProperty("column", 1);
item1ComboBox->addItems(methodBlocks.at(1).at(rowType));
QObject::connect(item1ComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnComboIndexChanged(const QString&)));
widgetParent->setItemWidget(childItem,1,item1ComboBox);
itemParent->addChild(childItem);
}
}
And this is where I try to create a text edit widget over one of the comboboxes
void customMethodConstructorWindow::OnComboIndexChanged(const QString& text)
{
QComboBox* combo = qobject_cast<QComboBox*>(sender());
if (combo)
{
int nRow = combo->property("row").toInt();
int nCol = combo->property("column").toInt();
switch (nRow) {
case 0:
{
switch (nCol)
{
case 0:
{
//combo->setVisible(false);
//testPoint = combo->pos();
}
break;
case 1:
{
if(combo->currentIndex() != 0)
{
QTreeWidgetItem *childItem = new QTreeWidgetItem(combo->property("itemParent").value<QTreeWidgetItem*>());
QTextEdit *textItemEdit = new QTextEdit;
//QObject::connect(item1ComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnComboIndexChanged(const QString&)));
ui->methodSetupTreeWidget->setItemWidget(childItem,2,textItemEdit);
}
}
break;
case 2:
//customObjectAttributes.comparisonType.push_back(combo->currentIndex());
break;
case 3:
{
//customObjectAttributes.valueB.push_back(combo->currentIndex());
}
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
//ui->logicSetupTableWidget->setRowCount(ui->logicSetupTableWidget->rowCount()+1);
if(combo->currentIndex() != 3)
{
//addComboRow(ui->logicSetupTableWidget->rowCount()-1);
}
//customObjectAttributes.outputType.push_back(combo->currentIndex());
break;
}
}
break;
case 1:
{
switch (combo->property("column").toInt())
{
case 0:
break;
case 1:
{
addChildRow(ui->methodSetupTreeWidget,ui->methodSetupTreeWidget->itemAt(QPoint(2,1)),0);
addChildRow(ui->methodSetupTreeWidget,ui->methodSetupTreeWidget->itemAt(QPoint(3,1)),1);
}
break;
case 2:
{
}
break;
case 3:
{
}
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
{
if(combo->currentIndex() != 3)
{
//addComboRow(ui->logicSetupTableWidget->rowCount()-1);
}
}
break;
}
}
break;
}
}
}
ScreenShot of current situation
My issue here is that the text edit shows up below the less than (<) combobox rather than ontop (or replacing it).
I was able to find a solution using QStandardItem:setData() and QStackedWidget to get the functionality I was after.
This was done in the process of trying to solve a related issue here.
Related
I have a QComboBox with several choices on a QToolBar. Every choice of the QComboBox will open a specific dialog window.
The problem I have is that after I choose the preferred index on the combobox no dialogs opens up. For simplicity of the example I am linking the same dialog to all choices:
dredgewindow.h
This is the header file
namespace Ui {
class DredgeWindow;
}
class DredgeWindow : public QMainWindow
{
Q_OBJECT
public:
explicit DredgeWindow(QWidget *parent = nullptr);
~DredgeWindow();
private:
Ui::DredgeWindow *ui;
DredgeDB *mDredgeDB;
};
dredgewindow.cpp
DredgeWindow::DredgeWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::DredgeWindow)
{
ui->setupUi(this);
QComboBox* myComboBox = new QComboBox;
ui->toolBarControls->addWidget(myComboBox);
myComboBox->addItem("Please Select");
myComboBox->addItem("Bucket");
myComboBox->addItem("Scow");
myComboBox->addItem("Hopper Dredger");
switch(myComboBox->currentIndex()){
case 0:
// do nothing
break;
case 1:
// Go to Bucket
mDredgeDB = new DredgeDB();
mDredgeDB->show();
break;
case 2:
// Go to Scow...
mDredgeDB = new DredgeDB();
mDredgeDB->show();
break;
case 3:
// Go to Hopper Dredger
mDredgeDB = new DredgeDB();
mDredgeDB->show();
default:
break;
}
}
DredgeWindow::~DredgeWindow()
{
delete ui;
}
So far I have been trying to trigger the opening of the dialogs using the combobox but as soon as I release the mouse (and therefore I switch - case) I expect the dialog to open but nothing happens. This source was useful even though it was not in c++. But still I used it to understand the general approach.
This approach triggers the combobox and set it active but other than that there is no specific indication.
Thanks in advance for pointing to the right direction for solving this problem.
You have to connect QComboBox::activated() signal to some slot.
Signals & Slots in Qt5
New Signal Slot Syntax
qOverload<>
This signal is sent when the user chooses an item in the combobox. The
item's index is passed. Note that this signal is sent even when the
choice is not changed. If you need to know when the choice actually
changes, use signal currentIndexChanged().
Note: Signal activated is overloaded in this class. To connect to this
signal by using the function pointer syntax, Qt provides a convenient
helper for obtaining the function pointer - qOverload<>.
class DredgeWindow : public QMainWindow
{
Q_OBJECT
...
private slots:
void on_combo_index_activated(int index);
...
};
DredgeWindow::DredgeWindow(QWidget *parent)
: QMainWindow(parent)
{
...
connect(myComboBox, QOverload<int>::of(&QComboBox::activated),
[=](int index) { on_combo_index_activated(index); });
...
}
void DredgeWindow::on_combo_index_activated(int index)
{
switch (index)
{
case 0:
// do nothing
break;
case 1:
// Go to Bucket
mDredgeDB = new DredgeDB();
mDredgeDB->show();
break;
case 2:
// Go to Scow...
mDredgeDB = new DredgeDB();
mDredgeDB->show();
break;
case 3:
// Go to Hopper Dredger
mDredgeDB = new DredgeDB();
mDredgeDB->show();
default:
break;
}
}
I have a class based on QGraphicsView. I want to make the clicks on WASD move the visible scene to the appropriate direction. The task is simple and clear, wrote the following code:
GameScene::GameScene(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene, parent) {
_scene = scene;
_resolution = new QPointF(1920, 1080);
_position = new QPointF(100, 100);
setSceneRect(_position->x(), _position->y(), _resolution->x(), _resolution->y());
installEventFilter(this);
scene->addItem(new QGraphicsLineItem(510, 510, 990, 990)); }
void GameScene::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_W:
_position->setY(_position->y() - 100);
break;
case Qt::Key_S:
_position->setY(_position->y() + 100);
break;
case Qt::Key_A:
_position->setX(_position->x() - 100);
break;
case Qt::Key_D:
_position->setX(_position->x() + 100);
break;
default:
break;
}
setSceneRect(_position->x(), _position->y(), _resolution->x(), _resolution->y());
update();
}
This code even works, but there is one problem: the scene does not always respond to the setSceneRect function (checked through the debagger signal reaches, the values are sent to the function correct), that is, the key is pressed, the keyPressEvent function is executed, the desired case is selected, the values are updated, but the setSceneRect function does not do anything. What could be the problem?
I am pretty new to cocos2d-x.I have created a button and i wanted to change the state of the button when i tap the button . i am having trouble changing the state from play to pause similar to a music player.Below is the code.
void Gallery::buttonUI(Size visibleSize,Vec2 origin)
{
button = Button::create("play.png");
//button->loadTextures("pause.png","play.png","pause.png");
button->setPosition(Point((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80));
button->setContentSize(Size(100.0f, button->getVirtualRendererSize().height));
button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
switch (type)
{
case Widget::TouchEventType::BEGAN:
break;
case Widget::TouchEventType::ENDED:
CCLOG("Characters: %c %c", 'a', 65);
if (!flag)
Gallery::pauseSong();
else
Gallery::resumeSong();
break;
default:
break;
}
});
this->addChild(button);
}
void Gallery::playSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
flag = false;
}
void Gallery::pauseSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
flag = true;
}
void Gallery::resumeSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
flag = false;
}
I don’t know of such methods for the ui::Button. But I don’t see the use of specific ui::Button items (capinsets, different methods for different touch events etc.) in your method also.
So, I think the MenuItemImage is better in your case:
bool flag = true;
MenuItemImage *button = MenuItemImage::create("play.png", "play_pressed.png", CC_CALLBACK_0(Gallery::playSong, this));
button->setPosition(Vec2((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80)); // better is use Vec2, Point can be ambiguous
Menu* menu = Menu::create(button, NULL); // add created button on Menu
menu ->setPosition(0,0);
this->addChild(menu);
And then set the images in handler pressing:
void Gallery::playSong()
{
if(flag)
{
// preload better move to AppDelegate.cpp
// CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
flag = false;
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
button->setNormalImage(Sprite::create(“pause.png”));
button->setSelectedImage(Sprite::create(“pause_pressed.png”)); // if you use selected image
}
else
{
flag = true;
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
button->setNormalImage(Sprite::create(“play.png”));
button->setSelectedImage(Sprite::create(“play_pressed.png”));
}
}
In cocos 3.x use property: setHighlighted(bool)
Example:
When press a key: button->setHighlighted(true);
When release the key:
button->setHighlighted(false);
I want to show or hide items in QStackedWidget. When I press Enter button it should show a stacked element and when I press say a left button it should hide.
I use QStackedWidget and QListWidget. My code:
mymainwindow.h:
#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H
class mymainwindow : public QMainWindow
{
Q_OBJECT
public:
mymainwindow();
protected:
void keyPressEvent(QKeyEvent *event);
private:
QStackedWidget *stack;
QListWidget *list;
QVBoxLayout *vertical;
QWidget *widget;
};
#endif
mymainwindow.cpp:
#include "mymainwindow.h"
mymainwindow::mymainwindow() : QMainWindow()
{
stack = new QStackedWidget();
list = new QListWidget();
stack->addWidget(new QLineEdit("Hello U have clicked the first menu"));
stack->addWidget(new QLineEdit("Second ListWidget Item"));
stack->addWidget(new QLineEdit("Last Widget Item"));
widget = new QWidget();
QLabel *label = new QLabel("Main Window");
list->addItem("New Item 1");
list->addItem("New Item 2");
list->addItem("New Item 3");
list->setFixedSize(200,100);
QVBoxLayout *vertical = new QVBoxLayout();
vertical->addWidget(label);
vertical->addWidget(list);
vertical->addWidget(stack);
widget->setLayout(vertical);
setCentralWidget(widget);
}
void mymainwindow::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Down:
connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int)));
break;
case Qt::Key_Up:
connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int)));
break;
case Qt::Key_Left:
break;
}
}
You will need to handle the Key_Left and Key_Enter cases in your key press event handler. It seems that you would simply like to show and hide the stackwidget based on the press of those two buttons. This is a simple QWidget operation, and the problem is not much related to QStackedWidget.
You would need to change the key press event code as follows:
void mymainwindow::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Down:
connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
break;
case Qt::Key_Up:
connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
break;
case Qt::Key_Left:
stack->show(); // <---- Added
break;
case Qt::Key_Enter: // <---- Added
stack->hide(); // <---- Added
break; // <---- Added
}
}
I'm trying get all the button child widgets of a window. The buttons were created through QDialogButtonBox. How do I get the which one is the cancel/ok/save button?
I have:
QWidget *pWin = QApplication::activeWindow();
QList<QPushButton *> allPButtons = pWin->findChildren<QPushButton *>();
QListIterator<QPushButton*> i(allPButtons);
while( i.hasNext() )
{
//identify which button is cancel/ok/save button here
/*Note: This is where I'm having trouble, getting the text of the
button here returns NULL. Any other way of Identifying which is
which?
Is it a special case when buttons are created through QDialogButtonBox?
*/
}
You should use the QDialogButtonBox::button() method, to get the button of the corresponding role.
For instance :
QPushButton* pOkButton = pButtonBox->button(QDialogButtonBox::Ok);
QPushButton* pCancelButton = pButtonBox->button(QDialogButtonBox::Cancel);
// and so on...
Generally speaking, I would say it's a bad idea to find a button from it's text, as this text might change when you app is internationalized.
One way is by text parameter from constructor such as QPushButton(const QString & text, QWidget * parent = 0):
QPushButton* buttonSave = new QPushButton("Save");
// etc..
while( i.hasNext() )
{
//identify which button is cancel/ok/save button here
if(i.next()->text() == "Save") {
// do something to save push button
}
}
Another alternative solution:
Use QDialogButtonBox's buttons function to return a list of all the buttons that have been added to the button box, then iterate over the list and identify each button using QDialogButtonBox's standardButton.
auto buttons = ui->buttonBox->buttons();
for (auto button : buttons) {
switch (ui->buttonBox->standardButton(button)) {
case QDialogButtonBox::Ok:
// do something
break;
case QDialogButtonBox::Cancel:
// do something
break;
case QDialogButtonBox::Save:
// do something
break;
default:
break;
}
}
For non-standard buttons
Map each button to an enum:
.h file:
private:
enum class NonStandardButton { Undo, Redo };
// map of non-standard buttons to enum class NonStandardButton
QHash<QAbstractButton*, NonStandardButton> buttonsMap;
.cpp file:
// in constructor
auto undoQPushButton =
ui->buttonBox->addButton("Undo", QDialogButtonBox::ActionRole);
auto redoQPushButton =
ui->buttonBox->addButton("Redo", QDialogButtonBox::ActionRole);
buttonsMap.insert(undoQPushButton, NonStandardButton::Undo);
buttonsMap.insert(redoQPushButton, NonStandardButton::Redo);
Then use QDialogButtonBox::NoButton to identify non-standard buttons:
switch (ui->buttonBox->standardButton(button)) {
case QDialogButtonBox::NoButton:
switch (buttonsMap.value(button)) {
case NonStandardButton::Undo:
// do something
break;
case NonStandardButton::Redo:
// do something
break;
default:
break;
}
default:
break;
}