QTreeView with QFileSystemModel: How can I remove all columns except "Name"? - c++

while I'm working on something in Qt5 that closely resembles a file manager, I try to implement a very basic tree view, showing only the directory names without any other information. However, (it seems that) QTreeView doesn't let me decide which columns I want to show.
Here's what I have:
// ...
QString m_path = "C:/Users/mine";
dirModel = new QFileSystemModel(this);
dirModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
dirModel->setRootPath(m_path);
ui->treeView->setModel(dirModel);
// ...
Now my QTreeView shows more information with the name, like the size et al.; however, this is not the desired behavior.
Setting headerVisible to false removes the "headline" of my QTreeView which is OK, but how can I remove the other columns completely? I tried:
ui->treeView->hideColumn(1);
just to test if that works, but it did not change a thing.

QTreeView* treeView = new QTreeView(centralWidget());
QFileSystemModel* fsModel = new QFileSystemModel(treeView);
fsModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
fsModel->setRootPath("/home/user");
treeView->setModel(fsModel);
// first column is the name
for (int i = 1; i < fsModel->columnCount(); ++i)
treeView->hideColumn(i);
QHBoxLayout* hLayout = new QHBoxLayout(centralWidget());
hLayout->addWidget(treeView);
Another approach here (PyQt but the logic is still the same): PyQt: removing unnecessary columns

There's nothing wrong with your approach. It works as below:
mainwindow header:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QFileSystemModel * dirModel;
};
mainwindow source:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QString m_path = "E:";
dirModel = new QFileSystemModel(this);
dirModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
dirModel->setRootPath(m_path);
ui->treeView->setModel(dirModel);
ui->treeView->hideColumn(1);
}

Related

How to sort a QListView by sorting in QTableView?

I have a QListView and QTableView both sharing a subclassed QSortFilterProxyModel on top of a custom source model. Sorting is enabled in the QTableView, how to share the same sorting result between two views?
Do I reimplement the sort() or lessThan() function of the QSortFilterProxyModel? If so, how should i reimplement them?
This is currently my code and it's not working:
MyModel *model = new QMyModel();
MySortFilterModel *proxy_model = new MySortFilterModel();
proxy_model->setSourceModel(model);
proxy_model->setDynamicSortFilter(true);
QListView *list = new QListView();
list->setModel(proxy_model);
QTableView *table = new QTableView();
table->setModel(proxy_model);
table->setSortingEnabled(true);
I have also tried the following:
QHeaderView *header = table->horizontalHeader();
header->setSortIndicator(0, Qt::AscendingOrder);
header->setSortIndicatorShown(true);
header->setSectionsClickable(true);
connect(header,SIGNAL(sectionClicked(int)),table,SLOT(sortByColumn(int)));
But when I sort the table by clicking the header, the table is updated but not the list, with both view having different items at different rows.
I would like to have a result such that when user clicks the horizontal header of the QTableView, the item data are sorted, meanwhile the same item data which are shared in the QListView are also being sorted.
I was interested the question. So I created an empty GUI project and implemented something like your first example. It seems my code do what you want. When I click the table header the QListView items resorts.
You can try it
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void mySetupUi();
Ui::MainWindow *ui;
QSortFilterProxyModel *proxyModel;
QStandardItemModel *sourceModel;
QTableView *tableView;
QListView *listView;
};
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
proxyModel(new QSortFilterProxyModel(this)),
tableView(new QTableView(this)),
listView(new QListView(this))
{
ui->setupUi(this);
sourceModel = getModel();
// set source model for proxy
proxyModel->setSourceModel(sourceModel);
tableView->setSortingEnabled(true);
// set proxy model for views
tableView->setModel(proxyModel);
listView->setModel(proxyModel);
mySetupUi();
}
void MainWindow::mySetupUi()
{
tableView->move(10, 15);
listView->move(300, 15);
tableView->adjustSize();
listView->adjustSize();
tableView->raise();
listView->raise();
}
model initialization (you can put it near the mainwindow constructor):
QStandardItemModel* getModel()
{
QStandardItemModel *model = new QStandardItemModel();
model->setItem(0, 0, new QStandardItem("Alex"));
model->setItem(0, 1, new QStandardItem("Brown"));
model->setItem(0, 2, new QStandardItem("24"));
model->setItem(1, 0, new QStandardItem("Mike"));
model->setItem(1, 1, new QStandardItem("White"));
model->setItem(1, 2, new QStandardItem("19"));
model->setItem(2, 0, new QStandardItem("Ben"));
model->setItem(2, 1, new QStandardItem("Black"));
model->setItem(2, 2, new QStandardItem("22"));
return model;
}
It looks as the same what you did. But it works.

How to disable the default copy behavior in QTreeView?

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.

qt how to add a groupbox that contains some widgets dynamically with a pushbutton?

I have a groupbox that contains some pushbuttons and sliders. I want that when I click on a button, a new groupbox that is the same with the former one should appear under the first one. Whenever I click on the button, same situation should happen dynamically. Since I need up to 32 groupbox like that, I don't want to put all groupboxes manually. So, how can I do this?
First off, a layout is highly recommended.
Here is an example (I have done this before). You can derive a class from QScrollArea, then set in the constructor the layouts you want to have.
In here a simple button called Add is in the window.
If you press it, a row gets added and initialized with default values (0, 0, 0) <- integers.
In the live program, I load the values from a file/database and initialize it then.
You may want to use different layout(s) and a different setup, but this should give you the idea. I'm sure you get where you want with a little more experimenting.
//Structure to keep track of the added widgets easier
struct ItemRow
{
ItemRow(QLineEdit *entry, QLineEdit *amount, QComboBox *box)
: m_Entry(entry)
, m_Amount(amount)
, m_Box(box)
{ }
ItemRow(void)
: m_Entry(nullptr)
, m_Amount(nullptr)
, m_Box(nullptr)
{ }
QLineEdit *m_Entry;
QLineEdit *m_Amount;
QComboBox *m_Box;
};
The class declaration.
class MyScrollArea : public QScrollArea
{
Q_OBJECT
public:
explicit MyScrollArea(QWidget *parent = 0);
~MyScrollArea();
//...
void OnAddButtonPressed(void);
void DrawButtonLayout(void);
void AddRow(int val1, int val2, int val3); //Use own parameters
private:
QVBoxLayout *m_LayoutFirstRow;
QVBoxLayout *m_LayoutSecondRow;
QVBoxLayout *m_LayoutThirdRow;
//...
QVBoxLayout *m_LayoutButton;
//...
QList<QPushButton*> m_Buttons;
QVector<ItemRow> m_ItemRows;
}
The implementation.
MyScrollArea::MyScrollArea(QWidget *parent) :
QScrollArea(parent),
ui(new Ui::MyScrollArea)
{
ui->setupUi(this);
setWidget(new QWidget);
setWidgetResizable(true);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
QHBoxLayout *mainLayout = new QHBoxLayout(this);
m_LayoutFirstRow = new QVBoxLayout();
m_LayoutSecondRow = new QVBoxLayout();
m_LayoutThirdRow = new QVBoxLayout();
m_LayoutButton = new QVBoxLayout();
widget()->setLayout(mainLayout);
mainLayout->addLayout(m_LayoutFirstRow);
mainLayout->addLayout(m_LayoutSecondRow);
mainLayout->addLayout(m_LayoutThirdRow);
mainLayout->addLayout(m_LayoutButton);
DrawButtonLayout();
}
RewardDialog::~RewardDialog()
{
delete ui;
}
void MyScrollArea::OnAddButtonPressed(void)
{
AddRow(0, 0, 0);
}
void MyScrollArea::DrawButtonLayout(void)
{
QPushButton *addBtn = new QPushButton("Add");
connect(addBtn, SIGNAL(clicked()), this, SLOT(OnAddButtonPressed()));
m_LayoutButton->addWidget(addBtn);
m_Buttons.push_back(addBtn); //Keep somewhere track of the button(s) if needed - example: put in QList (not the best approach though)
}
void MyScrollArea::AddRow(int val1, int val2, int val3)
{
QLineEdit *pEntry = new QLineEdit(QString::number(val1));
pEntry->setValidator(new QIntValidator());
QLineEdit *pAmount = new QLineEdit(QString::number(val2));
pAmount->setValidator(new QIntValidator());
QComboBox *pBox = new QComboBox();
InitComboBox(pBox, val3); //Initialize the combo-box (use connect if you wish) - code not included
m_LayoutFirstRow->addWidget(pEntry);
m_LayoutSecondRow->addWidget(pAmount);
m_LayoutThirdRow->addWidget(pBox);
ItemRow row;
row.m_Entry = pEntry;
row.m_Amount = pAmount;
row.m_Box = pBox;
m_ItemRows.push_back(row);
}
Leave a comment if something seems wrong, I put this together in Notepad++.
Note: The documentation-link is for QT4.8, as 5.3 is not available anymore, but my code is from version 5.3 too.

QGraphicsView Won't Expand

I'm having extreme trouble getting QWidgets to expand as needed. This isn't the first time I've run into this problem, and last time I solved it by hacking in a large sizeHint(). This is the WRONG approach and I would really like to learn the CORRECT approach.
If anyone could help me out it would be greatly appreciated. Here's what it looks like and the layouts I have written in code. If necessary I can supply the code. Please help me learn Layouts.
Edit: The first layout mock up actually works correctly. I am attaching another layout mockup which causes a problem.
Code. Three classes.
MainWindow Class:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget * w = new MainCentralWidget(this);
setCentralWidget(w);
}
MainCentralWidget Class:
MainCentralWidget::MainCentralWidget(QWidget *parent) :
QWidget(parent)
{
SetupLayout();
}
void MainCentralWidget::SetupLayout()
{
QVBoxLayout * main_layout;
QFormLayout * plugin_layout;
//Start
main_layout = new QVBoxLayout();
//Setup the plugin chooser
plugin_layout = new QFormLayout();
QComboBox * plugins_box = new QComboBox();
plugin_layout->addRow("Choose Plugin: ", plugins_box);
QFrame* line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
plugin_layout->addRow(line);
main_layout->insertLayout(0, plugin_layout);
main_layout->insertWidget(1, new SubWidget());
//Finish
setLayout(main_layout);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
SubWidget Class:
SubWidget::SubWidget(QWidget *parent) :
QWidget(parent)
{
setStyleSheet("QWidget { background: yellow }");
setMaximumSize(10000,10000);
setMinimumSize(100,100);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
SetupLayout();
//setMaximumSize(10000,10000);
}
void SubWidget::SetupLayout()
{
QHBoxLayout main_layout;
main_layout.setAlignment(Qt::AlignTop | Qt::AlignLeft);
main_layout.addWidget(&m_graphics_view);
m_graphics_view.setMaximumSize(10000,100000);
setLayout(&main_layout);
}
void SubWidget::SetupLayout()
{
QHBoxLayout main_layout;
main_layout.setAlignment(Qt::AlignTop | Qt::AlignLeft);
main_layout.addWidget(&m_graphics_view);
m_graphics_view.setMaximumSize(10000,100000);
setLayout(&main_layout);
}
Your main_layout gets destroyed immediately after SetupLayout finished, as it goes out of scope. So, actually, your SubWidget has no any layout. That is why widgets are shown incorrectly.

Issue with QLineEdit clear signal

I'm working with the Qt KDE Necessitas project. I have a project built in Qt Creator and I am installing the apk on an emulator API-15 (also tested on API-10).
The following code is setup to clear the text of two different QLineEdit objects when a button is clicked, but this isn't the case. Randomly, only one of the two QLineEdit objects are cleared.
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
public slots:
void slotClear();
private:
QLineEdit* line1;
QLineEdit* line2;
//...
};
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout* mainLayout = new QVBoxLayout;
QFormLayout* form = new QFormLayout;
line1 = new QLineEdit;
form->addRow(tr("Line 1: "), line1);
line2 = new QLineEdit;
form->addRow(tr("Line 2:"), line2);
QPushButton* button = new QPushButton;
mainLayout->addLayout(form);
mainLayout->addWidget(button);
QWidget* centralWid = new QWidget(this);
centralWid->setLayout(mainLayout);
this->setCentralWidget(centralWid);
connect(button, SIGNAL(clicked()), this, SLOT(slotClear()));
}
void MainWindow::slotClear()
{
line1->clear();
line2->clear();
}
//...
Calling the function QLineEdit::setText("") produces the same results. Additionally, connecting the clicked() signal from the button directly to the clear() slot of the QLineEdit has no effect.
I haven't been programming in Qt for very long, so I am unsure if there is something I am doing wrong. Is anybody seeing something needs to be corrected in order to have the text cleared from BOTH QLineEdits? I am not sure if this is unique to Qt itself or Qt Necessitas. Any input would be greatly appreciated.
EDIT
I have also just noticed that entering text in one line, switching to another line and entering text there, and then switching back to the original line results in the original text being erased once the field is clicked (note, the button was never clicked). I think this is a pretty clear indication that something funky is going on.
EDIT 2
Registered as a bug with KDE