Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

simple Notepad



  • I have followed a simple notepad tutorial and all seems good.
    Couple of questions. When I write in the notepad save the text file then change text - how do I get the app to recognise changes have been made, so that when I go to close the app it knows a change has happened and asks to save before close? Trivial I know but wonder if it can be done?

    Thanks James



  • @jamesmfarrow
    So it is your job to maintain a boolean flag, often called a "dirty" flag, to indicate whether the document has been changed since the last time it was saved. An unsaved changed file is referred to as being "dirty".

    You will want to connect a slot to whatever widget you are using --- say a QTextEdit --- on its textChanged signal, and the slot should set the dirty flag to true. When the user wants to quit you look at this flag and warn if it is set. Whenever the user saves the file you set the flag to false. So immediately after saving, and before any further editing, the user can exit without warning.

    Makes sense?



  • Thanks! I have found on_textEdit_textChanged();
    I now need to work out how to fit bit in like you said!

    Thanks again.



  • @jamesmfarrow
    Hint: it's just a member variable of something to do with your document, or even of your main window if that's all you've got.

    Further, if I'm not confusing you. If you are using a QTextEdit that has an associated underlying QTextDocument * document(). And that already has a pre-provided flag for this for you, Using QTextEdit as an Editor

    QTextDocument provides an isModified() function which will return true if the text has been modified since it was either loaded or since the last call to setModified with false as argument.

    So you could use that as your "dirty" flag. Clear that flag whenever you save. In this case, you won't even need to slot onto textChanged(), as QTextEdit will be setting the QTextDocument::setModified(true) for you behind the scenes when the user changes content. But I think it's as well to understand the explicit principle if you needed to implement for yourself.



  • Screenshot 2020-10-24 at 10.14.46.png
    looks like I am using Qtextedit - see what I can do!!



  • @jamesmfarrow
    That's a pretty big screenshot!

    Read my post just above which I made just before your latest post, explaining how you can achieve it without having to maintain the flag for yourself if you don't want to.



  • if(currentFile.isModified()) { std::cout << "modified" << std::endl; save();}
    else if(currentFile.isEmpty()) { std::cout << "empty" << std::endl; QApplication::quit(); }
    else QApplication::quit();

    When close is triggered, if file has changed - save it.
    if file is empty i.e. nothing has been typed simply quit.

    Problem is isEmpty is true even when I have typed - it must only change when file saved??



  • @jamesmfarrow
    I don't know what's going on with your isEmpty(), might depend where this code of yours is situated. I presume your currentFile is your textEdit->document(), and is correct? Don't call it currentFile, better currentDocument, or just use textEdit->document() whenever you want to access it, as that can change.

    You don't need to check isEmpty() here anyway. Either the file is modified and needs saving or it is not and does not, I think. Having said that, you may nonetheless wish to investigate what is going on with isEmpty() if you say the document is not empty. isEmpty() should reflect the state of the document, nothing to do with whether you have saved or not.



  • Here is the code, I made some big 'cock ups' and had to pull from git. Back to start :(
    As you can see currentFile is a QString not QDocument... ?

    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE

    class MainWindow : public QMainWindow
    {
    Q_OBJECT //base class handles events etc

    public:
    MainWindow(QWidget *parent = nullptr); //by passing in nullptr we are stating that it has no parents
    ~MainWindow(); //destructor
    bool not_saved{true};

    void save();
    

    private slots:
    void on_actionNew_triggered();

    void on_actionOPen_triggered();
    
    void on_actionSave_as_triggered();
    
    void on_actionPrint_triggered();
    
    void on_actionExit_triggered();
    
    void on_actionCut_triggered();
    
    void on_actionCopy_triggered();
    
    void on_actionPaste_triggered();
    
    void on_actionUndo_triggered();
    
    void on_actionRedo_triggered();
    
    bool on_textEdit_textChanged();
    

    private:
    Ui::MainWindow *ui;
    QString currentFile;

    };

    #include "mainwindow.h"
    #include "ui_mainwindow.h"

    MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    //set text edit widget (central) to take up all screen space
    this->setCentralWidget(ui->textEdit);
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::on_actionNew_triggered()
    {
    currentFile.clear();//clears file
    ui->textEdit->setText(QString()); //clear text edit widget
    }

    void MainWindow::on_actionOPen_triggered()
    {
    QString filename = QFileDialog::getOpenFileName((this), "Open the file");
    QFile file(filename); //object for reading/writing files
    currentFile = filename;
    if(!file.open(QIODevice::ReadOnly | QFile::Text)) {
    QMessageBox::warning(this, "Warning", "Can not open file " + file.errorString());
    return;
    }
    setWindowTitle(filename);
    QTextStream in(&file);
    QString text = in.readAll();
    ui->textEdit->setText(text);
    file.close();
    }

    void MainWindow::on_actionSave_as_triggered()
    {
    QString filename = QFileDialog::getSaveFileName(this, "Save as");
    QFile file(filename); //object for reading/writing files
    if(!file.open(QFile::WriteOnly | QFile::Text)) {
    QMessageBox::warning(this, "Warning", "Can not save file " + file.errorString());
    return;
    }
    currentFile = filename;
    setWindowTitle(filename);
    QTextStream out(&file);
    QString text = ui->textEdit->toPlainText();
    out << text;
    file.close();
    }

    void MainWindow::on_actionPrint_triggered()
    {
    QPrinter printer;
    printer.setPaperName("Photosmart 5520");
    QPrintDialog pDialog(&printer, this);
    if(pDialog.exec() == QDialog::Rejected) {
    QMessageBox::warning(this, "Warning", "Can not access printer");
    return;
    }
    ui->textEdit->print(&printer);
    }

    void MainWindow::save() {

    QMessageBox::StandardButton reply;
    reply = QMessageBox::question(this, "Test", "File not saved\n\nSave file ?", QMessageBox::Yes|QMessageBox::No);
    if (reply == QMessageBox::Yes) {
              on_actionSave_as_triggered();
        QApplication::quit();
      } else {
        QApplication::quit();
      }
    

    }

    void MainWindow::on_actionExit_triggered()
    {
    if(on_textEdit_textChanged()) save();
    else QApplication::quit();
    }

    void MainWindow::on_actionCopy_triggered()
    {
    ui->textEdit->copy();
    }

    void MainWindow::on_actionPaste_triggered()
    {
    ui->textEdit->paste();
    }

    void MainWindow::on_actionCut_triggered()
    {
    ui->textEdit->cut();
    }

    void MainWindow::on_actionUndo_triggered()
    {
    ui->textEdit->undo();
    }

    void MainWindow::on_actionRedo_triggered()
    {
    ui->textEdit->redo();
    }

    bool MainWindow::on_textEdit_textChanged()
    {
    return true;
    }



  • @jamesmfarrow said in simple Notepad:
    When you paste code in this forum, please use the Code toolbutton to put lines of just triple-backticks above & below your pasted code. See how much more readable that makes it for us? :)

    As you can see currentFile is a QString not QDocument... ?

    currentFile is the name of the file you choose to save. Calling isModified() or isEmpty() on that is nonsense --- and of course QString::isEmpty() always returns false on that for a non-empty filename. Sort out your usage of the current filename you wish to use, which has nothing to do with the document() your QTextEdit is editing.

    You are supposed to have read the references I gave you and understood that you are to call isModified()/isEmpty() on ui->textEdit->document(). Or, go back to my original maintain your own flag if you don't want to use that.

    void MainWindow::on_actionExit_triggered()
    {
    if(on_textEdit_textChanged()) save();
    else QApplication::quit();
    }
    

    Calling on_textEdit_textChanged() here is nonsense. (Not to mention that your on_textEdit_textChanged() always just goes return true;.) That is supposed to be a slot which gets called by the Qt infrastructure when you change the text (e.g. type a character into the QTextEdit), via QTextEdit::textChanged signal. Your check for save on exit is supposed to be, say,

    if (ui->textEdit->document()->isModified())
        save();
    

    At this point you have conceptual reading up to do. It's general programming, and I must leave you to find out your own stuff.



  • @JonB said in simple Notepad:

    Using QTextEdit as an Editor

    Thanks for your help - I appreciate it!! I started with C++ about 6 months ago and have been 'trying' to learn as much as I can when I can. This is my first attempt with Qt. Its good to have someone point out the mistakes etc.
    Apologies for not using codehooks.

    A big learning curve...! Rest assured I will go and try to implement your advice and knowledge - no doubt " I'll be back "

    Thanks again!



  • Thanks to JonB I have now managed to get things working as I want.


Log in to reply