I have a problem with a QWidget that contains a tree (QTreeView): I can display it if it is created as a widget on its own, and I cannot do the same if it is a subwidget of another higher level widget. In this second case, what I get is an empty widget without the tree.
This works:
QApplication testApp(argc, argv);
MyTree myTree;
testApp.exec();
This does not work:
class MainWindow : public QMainWindow
{
Q_OBJECT
QSplitter *spl1, *spl2;
QMdiArea *mdiArea;
QTableWidget *other;
public:
MainWindow();
void LoadTree();
MyTree *myTree;
};
MainWindow::MainWindow(QWidget *_parent)
: QMainWindow(_parent), myTree(0)
{
mdiArea = new QMdiArea;
other = new QTableWidget;
spl1 = new QSplitter(Qt::Vertical, this);
spl1->addWidget(mdiArea);
spl1->addWidget(other);
LoadTree();
spl2 = new QSplitter(Qt::Horizontal, this);
spl2->addWidget(myTree);
spl2->addWidget(spl1);
setCentralWidget(spl2);
}
void MainWindow::LoadTree()
{
myTree = new MyTree(this);
}
Here is the code common to the two cases (which should be OK):
class MyTree : public QWidget
{
Q_OBJECT
public:
explicit MyTree(QWidget *_parent = 0);
int RefreshTree();
private slots:
void HandleTreeWidgetEvent(QModelIndex);
private:
QWidget *parent;
QTreeView *pjrTree;
QTreeView *GetNewTree();
};
MyTree::MyTree(QWidget *_parent) :
QWidget(_parent),
parent(_parent)
{
pjrTree = GetNewTree();
if(pjrTree) {
if(parent == 0)
pjrTree->show();
}
else {
// Never gets here
}
}
QTreeView* MyTree::GetNewTree()
{
QFileSystemModel *model = new QFileSystemModel;
model->setReadOnly(true);
model->setRootPath("/my/path/");
QTreeView* pjrTree = new QTreeView;
pjrTree->setModel(model);
pjrTree->setRootIndex(model->index("/my/path/"));
QModelIndex index;
index = model->index(4, 1); // temp values - no effect
return pjrTree;
}
Is the tree view the only widget that does not display? I would suggest passing the splitter it will be contained in as the parent, rather than the main window, when you instantiate the tree.
Deriving the class MyTree from QTreeView, instead of having a pointer to QTreeView as a member variable, fixed my problem.
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 QTreeView with a QStandardItemModel and I would like to be able to prevent the user from copying the text of the items.
#include <QMainWindow>
#include <QStandardItemModel>
#include <QTreeView>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr) :
QMainWindow(parent)
{
auto *treeView = new QTreeView(this);
auto *model = new QStandardItemModel(this);
for (int n = 0; n < 5; n++)
model->appendRow(createItem(QString::number(n)));
treeView->setModel(model);
treeView->setContextMenuPolicy(Qt::NoContextMenu);
setCentralWidget(treeView);
}
private:
QStandardItem *createItem(const QString &name)
{
auto *item = new QStandardItem(name);
item->setFlags(Qt::ItemIsEnabled);
return item;
}
};
I have already made the items not editable and disabled the context menu. However, it is still possible for the user to click on an item and copy the text by pressing Ctrl+C. I can use Qt::NoItemFlags, but I want the items to be enabled.
How to accomplish that?
To disable the default copy behavior of QTreeView reimplement QTreeView::keyPressEvent in a subclass, e.g. TreeView, like that:
void TreeView::keyPressEvent(QKeyEvent *event)
{
if (!(event == QKeySequence::Copy))
QTreeView::keyPressEvent(event);
}
Then in your code instead of QTreeView:
auto *treeView = new QTreeView(this);
instantiate TreeView:
auto *treeView = new TreeView(this);
Alternatively, you can use installEventFilter to trap the keystroke events with having to subclass.
Main creates two QStackedWidget, class Body and class Bottom.
In class Body there is a button and when it is pressed it should change the text in the label in Bottom. The program crash when Body->button try to use the public function of Bottom which change the private label.
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//GRAPHIC INTERFACE
QStackedWidget *stackedWidget_body = new QStackedWidget;
QStackedWidget *stackedWidget_bottom = new QStackedWidget;
//create classe
Body * wBody ;
Bottom *wBottom;
wBody = new Body(wBottom); //pass the reference of the Bottom class, wBottom
wBottom = new Bottom();
//wBottom->setLLabel(); //this command will change the name of the label, it means that setLLabel works well
//insert the body widget
stackedWidget_body->addWidget(wBody);
//insert the bottom widget
stackedWidget_bottom->addWidget(wBottom);
//layout
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(stackedWidget_body);
layout->addWidget(stackedWidget_bottom);
//WINDOW
QWidget window;
window.setLayout(layout);
window.show();
a.exec();
return 0 ;
}
Body.h
namespace Ui {
class Body;
}
class Body : public QWidget
{
Q_OBJECT
public:
explicit Body(Bottom *_wBottom, QWidget *parent = 0);
~Body();
public slots:
void test(); // it will be called then the button will be pressed
private:
Ui::Body *ui;
Bottom *wBottom;
void testSend(Bottom *wBottom);
};
Body.cpp
Body::Body(Bottom *_wBottom, QWidget *parent) :
wBottom(_wBottom),
QWidget(parent),
ui(new Ui::Body)
{
QPushButton *button_standard2 = new QPushButton("test");
connect(button_standard2, SIGNAL(clicked(bool)),this, SLOT(test()));
//layout
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button_standard2);
this->setLayout(layout);
ui->setupUi(this);
}
Body::~Body()
{delete ui;}
void Body::test(){
testSend(wBottom);
}
void Body::testSend(Bottom *wBottomX)
{
wBottomX->setLLabel();
}
bottom.h
namespace Ui {
class Bottom;
}
class Bottom : public QWidget
{
Q_OBJECT
public:
explicit Bottom(QWidget *parent = 0);
~Bottom();
void setLLabel();
private:
Ui::Bottom *ui;
QLabel *bLabel;
};
bottom.cpp
Bottom::Bottom(QWidget *parent) :
QWidget(parent),
ui(new Ui::Bottom)
{
bLabel = new QLabel("Name");
//layout
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(bLabel);
//setLLabel(); //this functions does it work
this->setLayout(layout);
ui->setupUi(this);
}
Bottom::~Bottom()
{delete ui;}
void Bottom::setLLabel(){
std::cout<<"change";
Bottom::bLabel->setText("value"); //The problem is here, when the function is called from Body::testSend
}
Can you give me any tip?
//create classe
Body * wBody ;
Bottom *wBottom;
wBody = new Body(wBottom); //pass the reference of the Bottom class, wBottom
wBottom = new Bottom();
You are sending an invalid wBottom instance to wBody. Try interchanging the last two lines.
I'm developing a Qt app in C++
I have create a layout with button bar, TreeView...
The Treeview is defined in my MainWindow.cpp
MainWindow::MainWindow()
{
setWindowTitle(QString::fromUtf8("PULS"));
resize(800,600);
setUnifiedTitleAndToolBarOnMac(true);
createDeviceStatusBar();
createSectionBar();
createTreeView();
QWidget *MainWindowWidget = new QWidget();
QVBoxLayout *MainWindowLayout = new QVBoxLayout(MainWindowWidget);
BrowserSection = new QGroupBox();
QWidget *BrowserWidget = new QWidget();
QHBoxLayout *BrowserLayout = new QHBoxLayout(BrowserWidget);
BrowserLayout->addWidget(SectionBar);
BrowserLayout->addWidget(TreeSection);
BrowserSection->setLayout(BrowserLayout);
MainWindowLayout->addWidget(DeviceSection);
MainWindowLayout->addWidget(BrowserSection);
setCentralWidget(MainWindowWidget);
show();
}
The createSectionBar() is a layout defined as below:
void MainWindow::createSectionBar()
{
SectionBar = new QGroupBox();
QVBoxLayout *SectionBarlayout = new QVBoxLayout;
SectionBarlayout->setContentsMargins(QMargins(0,0,0,0));
MusicButton = new QPushButton();
MusicButton->setFixedSize(110,150);
MusicButton->setIcon(QIcon(":/images/music.png"));
MusicButton->setIconSize(QSize(90,144));
MusicButton->setFlat(true);
MusicButton->setAutoFillBackground(true);
connect(MusicButton, SIGNAL(clicked()), this, SLOT(MusicTreeFile()));
SectionBarlayout->addWidget(MusicButton);
SectionBar->setLayout(SectionBarlayout);
}
The createTreeView() is defined as below to enable TreeView and Items.
void MainWindow::createTreeView()
{
TreeSection = new QGroupBox();
QVBoxLayout *TreeLayout = new QVBoxLayout;
MyTree = new TreeWidget();
MyTree->setSortingEnabled(true);
MyTree->setColumnWidth(0, 400);
QTreeWidgetItem* headerItem = new QTreeWidgetItem();
headerItem->setText(0,QString("File Name"));
headerItem->setText(1,QString("Size (Bytes)"));
headerItem->setText(2,QString("Date"));
MyTree->setHeaderItem(headerItem);
MyTree->setAutoFillBackground(true);
TreeLayout->addWidget(MyTree);
TreeSection->setLayout(TreeLayout);
}
What I need is to find a way to file the MyTree with
while (file != NULL && file->parent_id == folder_parent) {
QTreeWidgetItem* item = new QTreeWidgetItem();
int i;
LIBMTP_file_t *oldfile;
item->setText(0,file->filename);
Tree->addTopLevelItem(item);
....
}
here is the header file:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
protected:
private slots:
void MusicTreeFile();
private:
void createSectionBar();
void createTreeView();
void createDeviceStatusBar();
QGroupBox *SectionBar;
QGroupBox *TreeSection;
QGroupBox *DeviceSection;
QGroupBox *BrowserSection;
QPushButton *MusicButton;
TreeWidget *MyTree;
};
but it needs to be done only when clicking on MusicPushButton, I have already connected the MusicTreeFile() to the PushButton() action. but how to access to MyTree as it's also defined in another class..
You do not connect a signal to a class. You connect it to an instance of a class. And both of your instances are defined in MainWindow. So after both widgets are created you can call
QObject::connect(this->MusicButton, SIGNAL(clicked()), this->MyTree, SLOT(slot_name()));
With slot_name being your function
TreeWidget::slot_name{
while (file != NULL && file->parent_id == folder_parent) {
....
}
}
I create a window which inherits from QWidget
I set a grid layout to that Window
I make a function called handleHeroChange(int index) in public slot inside that window
I add a Qcombobox to call the function handleHeroChange(int index).
Qtcreator keeps telling:
**QObject::connect: No such slot QWidget::handleHeroChange(int) in ../Testing/Window.cpp:92**
What did i do wrong?
THE CODE:
//Window.h
class Window : public QWidget
{
QGraphicsPixmapItem* avatar;
QGraphicsTextItem* heroNameItem;
QGraphicsTextItem* heroStrItem;
QGraphicsTextItem* heroDexItem;
QGraphicsTextItem* herointelItem;
public:
Window(QWidget *parent = 0);
public slots:
void handleHeroChange(int);
};
//Window.cpp
Window::Window(QWidget *parent)
: QWidget(parent)
{
QGridLayout *grid = new QGridLayout(this);
QComboBox *comboHeroClass = new QComboBox();
comboHeroClass->addItem("Witcher");
comboHeroClass->addItem("Maurander");
comboHeroClass->setCurrentIndex(1);
grid->addWidget(comboHeroClass, 2,3,1,1);
QComboBox::connect(comboHeroClass, SIGNAL(currentIndexChanged(int)),this, SLOT(handleHeroChange(int)));
}
void Window::handleHeroChange(int index){
QPixmap myImage;
if(index == 0){
}else if(index == 1){
}
}
class Window : public QWidget
{
Q_OBJECT
Add Q_OBJECT macro without semicolon to your class and rebuild your project.
Without this macro moc cannot find your class and doesn't create your slot(and some other things) That's why you get your error: you see your slot but it doesn't exist and you get runtime error