In my project, I have a QVector full of QStrings containing file paths/names that don't actually exist on any drive:
QVector<QString> fileNames["level.dat", "data/villages.dat", "players/player1.dat"]//etc
I want to create a tree in my QTreeWidget that resembles a sort of file directory like this:
How would I go about creating something like this quickly and efficiently?
Thanks for your time :)
This solution does not avoid duplicate, so if you need that in the future, you could extend this piece of code with adding valiation for that. Anyway, this code produces the exact ame output for me that you have just described to wish to have.
main.cpp
#include <QTreeWidget>
#include <QStringList>
#include <QApplication>
int main(int argc, char **argv)
{
QApplication application(argc, argv);
QStringList fileNames{"level.dat", "data/villages.dat", "players/player1.dat"};
QTreeWidget treeWidget;
treeWidget.setColumnCount(1);
for (const auto& filename : fileNames) {
QTreeWidgetItem *parentTreeItem = new QTreeWidgetItem(&treeWidget);
parentTreeItem->setText(0, filename.split('/').first());
QStringList filenameParts = filename.split('/').mid(1);
for (const auto& filenamePart : filenameParts) {
QTreeWidgetItem *treeItem = new QTreeWidgetItem();
treeItem->setText(0, filenamePart);
parentTreeItem->addChild(treeItem);
parentTreeItem = treeItem;
}
}
treeWidget.show();
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++14
SOURCES += main.cpp
Build and Run
qmake && make && ./main
On a site node: you ought to use QStringList rather than QVector. In addition, your current initialization attempt surely results in compiler error. That is invalid initialization.
Related
I am trying to create a multiple level sub-menus in my Qt app.
For this purpose, I am using a vector with directories' tree, example is:
C:\Users\meine\Main_menu_dir\folder_1\sub1
C:\Users\meine\Main_menu_dir\folder_1\sub2
C:\Users\meine\Main_menu_dir\folder_1\sub2\subsub1
C:\Users\meine\Main_menu_dir\folder_2\sub1
C:\Users\meine\Main_menu_dir\folder_2\sub1\subsub1
C:\Users\meine\Main_menu_dir\folder_2\sub2\subsub1
C:\Users\meine\Main_menu_dir\folder_2\sub2\subsub2
I am using boost lib as follow:
#include "boost/filesystem.hpp"
#include <iostream>
namespace fs = ::boost::filesystem;
I am using an iterator to go trough the string of names and create the submenu tree:
for (// iter --> iterator in the list of files//)
{
if (fs::is_directory(*iter)) // from boost lib
{
QMenu *subMenu; // create a QMenu object
// name --> name of the directory, i.e.: folder_1, sub1, sub2, ....
subMenu = new QMenu(QString::fromStdString(name), recursiveMenu);
recursiveMenu->addMenu(subMenu);
}
}
in this way I create all the sub-menus under folder_1 (or, equivalently under Main_menu_dir depending from the starting point in the iterator). recursiveMenu is the menu at which I am appending the submenus. Maybe I should update it, something like:
recursiveMenu = subMenu;
How I can change the Menu structure to have the following menu levels:
1. Folder_1
1.1 sub1
1.2 sub2
1.2.1 subsub1
2. Folder_2
2.1 sub1
2.1.1 subsub1
2.1.2 subsub2
....
Thanks a lot.
Using QDirIterator with QFileInfo:
#include <QtWidgets>
static void fill_menu(QMenu *menu, const QString & path, const QString & prefix={}){
QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
int number = 0;
while (it.hasNext()) {
number++;
QString newprefix = QString::number(number);
if(!prefix.isEmpty())
newprefix.prepend(prefix + ".");
QFileInfo info(it.next());
QString name = newprefix + " " + info.fileName();
if(info.isDir()){
QMenu *dirmenu = menu->addMenu(name);
fill_menu(dirmenu, info.absoluteFilePath(), newprefix);
}
else if(info.isFile()){
menu->addAction(name);
}
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString directory{QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)};
QMainWindow w;
QMenu menu{"Files"};
w.menuBar()->addMenu(&menu);
fill_menu(&menu, directory);
w.show();
return a.exec();
}
Having a QLineEdit with a plain vanilla QStringList QCompleter. I wonder if I can change the appearance of the dropdown (I want to have either a min. size or smaller scrollbar).
Clarification: I want to set it in a stylesheet, not in the code.
Summary of my findings so far:
Pretty good summary here: https://forum.qt.io/topic/26703/solved-stylize-using-css-and-editable-qcombobox-s-completions-list-view/12
I have to use QStyledItemDelegate and
give the popup a name for the qss selector
I have tried that and it does not work for me, but seems to work for others
A simple straight forward solution is to set the stylesheet of the QScrollBar used by the popup of the QCompleter. My knowledge of qss is little, so I don't know if you can set a minimum size that way, but you can always have a look at verticalScrollBar().
Here is some code for the qss way:
#include <QAbstractItemView>
#include <QCompleter>
#include <QLineEdit>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineEdit edit;
edit.show();
QStringList completionList;
for (int a = 0 ; a < 10 ; ++a) {
completionList << QString("test%1").arg(a);
}
QCompleter completer(completionList);
edit.setCompleter(&completer);
QAbstractItemView *popup = completer.popup();
popup->setStyleSheet("QScrollBar{ width: 50px;}");
return a.exec();
}
I'm trying to generate a simple table (2 rows and 2 columns) and write it to a pdf file, using Qt 4.8.0.
So far, I generate the pdf but there is extra space at the bottom of the "printed" table:
I got the same problem with the right side of the table but I managed to get rid of it. But in this case I am clueless.
Here's the code I have now (all of this code is located in main.cpp):
Main
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtGui/QPrinter>
#include <QtGui/QHeaderView>
#include <QtGui/QPainter>
#include <QtGui/QTableWidget>
#include <QtGui/QTableWidgetItem>
/**/
/* Here are the functions.
/**/
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QMap<QString,int> values;
values.insert("X",7);
values.insert("Y",13);
bool status = TableWidgetToPdf("FromWidget.pdf",values);
return a.exec();
}
TableWidgetToPdf
bool TableWidgetToPdf(const QString& title, const QMap<QString, int>& values) {
QTableWidget* table = GenerateTable(values);
QPrinter printer;
printer.setOutputFileName(title);
printer.setOutputFormat(QPrinter::PdfFormat);
QPainter painter(&printer);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
printer.setPaperSize(QPrinter::A4);
table->render(&painter);
painter.end();
printer.newPage();
delete table;
return true;
};
GenerateTable
QTableWidget* GenerateTable(const QMap<QString,int>& values) {
QTableWidget* table = new QTableWidget;
table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
table->setRowCount(2);
table->setColumnCount(2);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
table->setShowGrid(false);
table->verticalHeader()->hide();
QStringList h_labels;
h_labels << "X" << "Y";
table->setHorizontalHeaderLabels(h_labels);
table->horizontalHeader()->setFont( QFont("Times", 10, QFont::Bold) );
table->horizontalHeader()->setStretchLastSection(true);
QTableWidgetItem* item00 = new QTableWidgetItem( QString::number(values["X"]));
item00->setTextAlignment(Qt::AlignCenter);
table->setItem(0,0, item00 );
QTableWidgetItem* item01 = new QTableWidgetItem( QString::number(values["Y"]) );
item01->setTextAlignment(Qt::AlignCenter);
table->setItem(0,1,item01);
table->setItem(1,0,new QTableWidgetItem("ABCD"));
return table;
};
NOTE:
Putting
table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
in GenerateTable the space disappears, but the cells are resized and consume too much space than needed for their contents. I would like to avoid that if possible:
EDIT:
OK.
In the end I achieved what I wanted by getting rid of the QTableWidget. I had to create the table using html and feeding it to a QTextEditor. Isn't any way to achieve this with a QTableWidget?
Have you tried the flags for resize content?
Try the following code, I don't have access to Qt right now.
table->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
table->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
Hope that works!
I realise that this is an old post but it seems fairly often read.
I tried the same methods that you tried and none worked. Eventually I used a QTableView and added an extra method called by adding/removing rows.
void
TitleView::verticalResizeTableViewToContents()
{
auto count = m_model->rowCount(QModelIndex());
auto scrollBarHeight = horizontalScrollBar()->height();
auto horizontalHeaderHeight = horizontalHeader()->height();
auto rowTotalHeight = scrollBarHeight + (horizontalHeaderHeight * count);
setMinimumHeight(rowTotalHeight);
setMaximumHeight(rowTotalHeight);
}
Pretty simple task but I didn't manage to find anything useful in documentation. I want a QTreeView to contain a single column called "Files" with data from QFileSystemView. Here's what I've got:
QFileSystemModel *projectFiles = new QFileSystemModel();
projectFiles->setRootPath(QDir::currentPath());
ui->filesTree->setModel(projectFiles);
ui->filesTree->setRootIndex(projectFiles->index(QDir::currentPath()));
// hide all but first column
for (int i = 3; i > 0; --i)
{
ui->filesTree->hideColumn(i);
}
That gives me a single column with "Name" header. How do I rename this header?
QAbstractItemModel::setHeaderData() should work. If not, you can always inherit from QFileSystemModel and override headerData().
Quick but a little dirty trick (please note w.hideColumn()):
#include <QApplication>
#include <QFileSystemModel>
#include <QTreeView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTreeView w;
QFileSystemModel m;
m.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
m.setRootPath("C:\\");
w.setModel(&m);
w.setRootIndex(m.index(m.rootPath()));
w.hideColumn(3);
w.hideColumn(2);
w.hideColumn(1);
w.show();
return a.exec();
}
You can subclass QFileSystemModel and overide method headerData(). For example, if you want only to change first header label and leave the rest with their original values, you can do:
QVariant MyFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const {
if ((section == 0) && (role == Qt::DisplayRole)) {
return "Folder";
} else {
return QFileSystemModel::headerData(section,orientation,role);
}
}
I was reading MVC tutorial and wanted to try out the code, but for some reason (which I'm not able to figure out) it is not working.
This code is suppose to show contents of current directory in QListWidget.
#include <QApplication>
#include <QFileSystemModel>
#include <QModelIndex>
#include <QListWidget>
#include <QListView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileSystemModel *model = new QFileSystemModel;
QString dir = QDir::currentPath();
model->setRootPath(dir);
QModelIndex parentIndex = model->index(dir);
int numRows = model->rowCount(parentIndex);
QListWidget *list = new QListWidget;
QListWidgetItem *newItem = new QListWidgetItem;
for(int row = 0; row < numRows; ++row) {
QModelIndex index = model->index(row, 0, parentIndex);
QString text = model->data(index, Qt::DisplayRole).toString();
newItem->setText(text);
list->insertItem(row, newItem);
}
list->show();
return a.exec();
}
There are 2 problems.
The first described by Frank Osterfeld's answer. Move:
QListWidgetItem *newItem = new QListWidgetItem;
into your loop.
The second has to do with QFileSystemModel's threading model. from the docs for QFileSystemModel:
Unlike the QDirModel, QFileSystemModel uses a separate thread to populate itself so it will not cause the main thread to hang as the file system is being queried. Calls to rowCount() will return 0 until the model populates a directory.
and
Note: QFileSystemModel requires an instance of a GUI application.
I don't think QFileSystemModel() will work properly until after the Qt event loop is running (which is started by a.exec() in your example).
In your case, model->rowCount(parentIndex) returns 0, even though there are items in the directory (at least that's what it's doing on my test).
Replacing QFileSystemModel with QDirModel (and removing the model->setRootPath(dir) call, which QDirModel` doesn't support) populates the list.
You must create a new item for each row. Move
QListWidgetItem *newItem = new QListWidgetItem;
into the for loop.