The TreeModel creation of the drive was successful using TreeWidget. However, when I clicked on a folder, the children of that folder kept being created, and I tried many times to prevent it, but it kept failing.
connect(ui->treeWidget, &QTreeWidget::itemClicked, this, &QtWidgetsApplication1::Addtree);
void QtWidgetsApplication1::Addtree(QTreeWidgetItem *root4, int column)
{
QDir* rootDir = new QDir(root4->text(2));
QDir test(root4->text(2));
QFileInfoList filesList = rootDir->entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
foreach(QFileInfo fileInfo, filesList)
{
QTreeWidgetItem* child = new QTreeWidgetItem();
child->setText(0, fileInfo.fileName());
if (fileInfo.isDir())
{
QIcon BasicIcon = mpIconProvider->icon(fileInfo);
child->setIcon(0, BasicIcon);
child->setText(2, fileInfo.filePath());
//child->setCheckState(1, Qt::Checked);
}
root4->addChild(child);
ui->treeWidget->addTopLevelItem(root4);
}
}
The code associated with itemClicked to create a child folder is as follows, and I'm not sure how to add it here to limit it to create it once.
Related
I'm trying to create my own custom folder tree model using QStandardItemModel. I succeeded in making it using TreeWidget, but the correct address was not printed, so I used the QStandardItemModel where the index is stored.
However, I'm leaving a question because I'm stuck in many ways and I want to get some advice on this.
void QtWidgetsApplication1::AddDocTree(QStandardItem *DocItem, QString Path)
{
QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QDir* rootDir = new QDir(path);
QFileInfoList filesList = rootDir->entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
DocItem = TestModel->invisibleRootItem();
foreach(QFileInfo fileInfo, filesList)
{
if (fileInfo.isFile())
{
QIcon BasicIcon = mpIconProvider->icon(fileInfo);
child = new QStandardItem(BasicIcon, fileInfo.fileName());
child->setAccessibleDescription(fileInfo.filePath());
}
else
{
QIcon BasicIcon = mpIconProvider->icon(fileInfo);
child = new QStandardItem(BasicIcon, fileInfo.fileName());
child->setAccessibleDescription(fileInfo.filePath());
}
DocItem->appendRow(child);
AddDocTree(child, fileInfo.filePath());
DocItem = child;
}
}
I have a drive model that we've already created using the QFilesystemModel, but ultimately we have to create a folder tree that looks like a Windows File Explorer.
To make it clear, I'm creating a treeview that will instantiate itself after the user creates a folder and said folder will be added as treeitem.
I currently have this:
TreeView treeView = new TreeView();
// Create new folder
MenuItem menuItem1 = new MenuItem("Create New Folder");
menuItem1.setOnAction(e -> {
System.out.println("Please name your directory:");
Scanner in = new Scanner(System.in);
String strFolder = in. nextLine();
createFolder(strFolder); // Create folder
TreeItem rootFolder = new TreeItem(strFolder); // Create new TreeItem
treeView.setRoot(rootFolder); // Replace old folder with new one
// rootFolder.getChildren().add(rootFolder);
// rootItem.getChildren().add(rootFolder);
});
After the treeView, I declared a new Menu Item that which will trigger an event after being clicked on.
The event will ask the user for a name to use as the root folder for the treeView. Now thats working fine.
Now what I'm having troubles with, is how to create more folders inside the root folder created and display them as subfolders in the treeView?
So far my code only does replace the old root folder by the new one created. Instead of setting the root folder again, how can i make it so it just adds those folders inside the first one and display them - again - in the treeView as subfolders?
Did I explain myself?
Thanks.
Simply add TreeItem(s) to the child list of the TreeItem. The following example replaces the root, if no items are selected and otherwise adds the new item as a child of the selected one:
TreeView<String> treeView = new TreeView<>(); // never use raw type without good reason
// Create new folder
MenuItem menuItem1 = new MenuItem("Create New Folder");
menuItem1.setOnAction(e -> {
TextInputDialog dialog = new TextInputDialog(); // replacing console input with dialog here
dialog.setHeaderText("Please name your directory:");
String strFolder = dialog.showAndWait().orElse(null);
if (strFolder != null) {
TreeItem<String> newFolder = new TreeItem<>(strFolder); // Create new TreeItem
TreeItem<String> selection = treeView.getSelectionModel().getSelectedItem();
createFolder(strFolder); // Create folder ; TODO: make dependent on parent???
if (selection == null) {
treeView.setRoot(newFolder); // Replace old folder with new one
} else {
selection.getChildren().add(newFolder);
selection.setExpanded(true); // make sure we're able to see the new child
}
}
});
I have a program which when it runs, at first the user is asked to initialize the system. In that question form, there are 3 checkboxes that the user can check them for specific person or every persons and the system initializes the items related to that checkbox for the person(s).
When a checkbox is selected, a specific function and subsequently the specific class is called and initialization is done.
In the mainwindow.cpp I have:
InitializeDialog *id=new InitializeDialog;
connect(id,&InitializeDialog::initializeSignal,this,&MainWindow::initializeSlot);
id->exec();
id is the question form which has 3 checkboxes in it. And:
void MainWindow::initializeSlot(QStringList persons, bool interests, bool plots, bool graphs)
{
initializeMBox->setWindowTitle(tr("Initializing System")+"...");
initializeMBox->setText(tr("Please wait until initialization has been done") + ".<br>");
initializeMBox->show();
initializeMBox->setStandardButtons(0);
if (interests)//checkbox 1 is checked
initializeInterests(persons);
if (plots)//checkbox 2 is checked
initializePlots(persons);
if(graphs)//checkbox 3 is checked
initializeGraphs(persons);
initializeMBox->setStandardButtons(QMessageBox::Ok);
}
And again:
void MainWindow::initializeInterests(QStringList persons)
{
for(int p=0;p<persons_comboBox_->count();p++)
{
persons_comboBox_->setCurrentIndex(p);
if (persons.contains(persons_comboBox_->currentText()))
{
//..
//create a specific class object and some specific functions
//..
//*
initializeMBox->setText(initializeMBox->text() + "<div><img src=\":/tickIcon.png\" height=\"10\" width=\"10\">" + " " + tr("Interests analyzed for the persons") + ": " + persons_comboBox_->currentText() + ".</div>");
}
}
}
initializePlots and initializeGraphs are similiar to initializeInterests.
The problem starts from here:
I want to show a message after initialization for every person (as I mentioned by star in initializeInterests) but my initializeMBox (is a QMessageBox) does not show the message continuously and when all persons are initialized, all messages are shown suddenly. It should be noted that I see my initializeMBox is getting bigger but it seems that my QMessageBox is Freezed.
I can't use QtConcurrent::run because my QMessageBox is updated from mainwindow (and so from the base thread) by the line that I mentioned by star.
How can I have a QMessageBox which be updated continuously?
Don't reenter the event loop. Replace id->exec() with id->show(). Manage the dialog's lifetime - perhaps it shouldn't be dynamically created at all.
Don't block in initializeInterests. Instead of changing the combo box, get its data, send it out to an async job, set everything up there, then send the results back.
Pass containers by const reference, not value.
Don't create strings by concatenation.
If the input persons list is long, sort it to speed up look-ups.
For example:
class StringSignal : public QObject {
Q_OBJECT
public:
Q_SIGNAL void signal(const QString &);
};
void MainWindow::initializeInterests(const QStringList &personsIn) {
auto in = personsIn;
std::sort(in.begin(), in.end());
QStringList persons;
persons.reserve(in.size());
for (int i = 0; i < persons_comboBox_->count(); ++i) {
auto const combo = persons_comboBox->itemText(i);
if (std::binary_search(in.begin(), in.end(), combo))
persons << combo;
}
QtConcurrent::run([persons = std::move(persons), w = this](){
StringSignal source;
connect(&source, &StringSignal::signal, w, [w](const QString & person){
w->initalizeMBox->setText(
QStringLiteral("%1 <div><img src=...> %2: %3.</div>")
.arg(w->initalizeMBox->text())
.arg(tr("Interests analyzed for the person"))
.arg(person)
);
});
for (auto &person : persons) { // persons is const
// create a specific object etc.
QThread::sleep(1); // let's pretend we work hard here
source.signal(person);
}
});
}
The creation of the "specific objects" you allude to should not access anything in the gui thread. If it doesn't - pass a copy of the required data, or access it in a thread-safe manner. Sometimes it makes sense, instead of copying the data, move it into the worker, and then when the worker is done - move it back into the gui, by the way of a lambda.
I am creating an application for project management which has various features including saving and opening the saved file. My application is running smoothly but i want to add another feature in the application which will allow it to save the data after some time.
Here is my code for the save and save as functions.
#FXML
private void handleSave() {
File userstoryFile = mainApp.getUserStoryFilePath();
if (userstoryFile != null) {
mainApp.saveUserStoryDataToFile(userstoryFile);
} else {
handleSaveAs();
}
}
/**
* Opens a FileChooser to let the user select a file to save to.
*/
#FXML
private void handleSaveAs() {
FileChooser fileChooser = new FileChooser();
// Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(
"XML files (*.xml)", "*.xml");
fileChooser.getExtensionFilters().add(extFilter);
// Show save file dialog
File file = fileChooser.showSaveDialog(mainApp.getPrimaryStage());
if (file != null) {
// Make sure it has the correct extension
if (!file.getPath().endsWith(".xml")) {
file = new File(file.getPath() + ".xml");
}
mainApp.saveUserStoryDataToFile(file);
}
}
Is it possible to add autosave feature here ( using timer function )? if yes, How?
click here to get complete application code
Something like this should be easy to implement using ScheduledExecutorService:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(() -> mainApp.saveUserStoryDataToFile(file), 0, 1, TimeUnit.MINUTES);
For saving the data with a delay of one minute between saves (no initial delay).
Note that using this approach you need to take care of a few things:
Synchronize access to the data.
Prevent concurrent access to the file.
Making sure shutdown is called when (or before) the JavaFX platform exits.
I'm new to Qt (previous experience is mostly Java) and am trying to find a good way of creating child directories and files given a QDir parent (and hold onto/create the QDir for the new child).
I've come up with a method to do this (I think!), but was unsure if this is the right way, or if there is already something built in that would do this for me.
Hope you can help.
QDir* MyClass::createChildDir(QDir* parent, QString dirName)
{
parent->mkdir(dirName);
QString newPath = parent->filePath(dirName);
QDir* newDir = new QDir(newPath);
return newDir;
}