Creating QActions on the fly for history



  • Hello everyone,

    I have been working on the 'history' feature of my web browser, and I have hit a bit of a wall. I have a menu called HistoryMenu, inside HistoryMenu would be QActions for each history entry. The problem I am facing has to do with the QActions. For every URL visited I would like to create a QAction containing the URL of the page visited. These QActions are created in the addToHistory slot. the goToHistoryURL slot is called when one of the QActions is clicked. I am not sure how to create a different QAction for every URL visited, so I have made one called historyAction. This performs well, except that when clicked it will only take me to the last URL I was at. I think I need to have different QActions for every URL, but I'm not sure. How do I create different QActions on the fly and then call the URL when I click it?
    here is my code so far:

    @void browseTab::addToHistory()
    {
    QString url = webView->url().toString();

    QString historyEntry = url;
    
    historyAction = new QAction(this);
    historyAction->setText(historyEntry);
    historyAction->setData(historyEntry);
    HistoryMenu->addAction(historyAction);
    connect(historyAction, SIGNAL(triggered()), SLOT(goToHistoryURL()));
    

    }

    void browseTab::goToHistoryURL()
    {
    webView->setUrl(QUrl(historyAction->text()));
    }
    @

    Example code would be great!

    Thank you!


  • Lifetime Qt Champion

    Hi,

    That's normal, calling historyAction->text() will always return the last action you created. You can use sender() in your slot to retrieve which action was triggered.

    Beware of one thing: you don't have any control regarding the number of actions you currently have



  • So would I use this?

    @connect(historyAction, SIGNAL(triggered()), sender, SLOT(goToHistoryURL()));@

    How can I set it to show only the last 10 or so entries? I don't want a menu of 1,000 QActions haha!


  • Lifetime Qt Champion

    If it's some form of "Recent file" you could use a QQueue and when it's getting full e.g. 10 elements, remove the oldest and delete it



  • I don't have a file, how do I put the sender() into the slot?


  • Lifetime Qt Champion

    I meant "Recent File" menu like you have in e.g. Qt Creator

    @
    void MyClass::mySlot()
    {
    QObject *senderObject = sender();
    // rest of your code
    }
    @



  • Oh okay, sorry I misunderstood you.

    So would I call senderObject in the connect() as well as the slot? Would it have to be in both slots?


  • Lifetime Qt Champion

    Have a look at the "Recent File" example in Qt's documentation it shows a variation of the technique nicely



  • I checked out the 'Recent File' example, and it is really helpful! I have a small problem though that I don't know how to fix.
    Here is my code thus far:
    @void browseTab::addToHistory()
    {
    QString url = webView->url().toString();

    QString historyEntry = url;
    
    QString title = webView->title();
    
    QIcon icon = webView->icon();
    
    int numRecentHistory = 1;
    
    for (int i = 0; i < numRecentHistory; ++i)
    {
        QString text = tr("&%1").arg(title);
    
        historyAction = new QAction(this);
        historyAction->setText(text);
        historyAction->setData(historyEntry);
        historyAction->setIcon(webView->icon());
        historyAction->setIconVisibleInMenu(true);
        HistoryMenu->addAction(historyAction);
        connect(historyAction, SIGNAL(triggered()), SLOT(goToHistoryURL()));
    }
    

    }

    void browseTab::goToHistoryURL()
    {
    QAction *action = qobject_cast<QAction *>(sender());
    if (action)
    loadHistory(action->data().toString());
    }

    void browseTab::loadHistory(const QString &name)
    {
    webView->setUrl(QUrl(QString(name)));
    }
    @

    When my webView finishes loading a URL, it calls addToHistory() which adds a new QAction. When this QAction is triggered, it calls goToHistoryURL(). goToHistoryURL() in turn calls loadHistory() which sets the webView to the URL enclosed in the QActions data() property. When I run the program, it runs great until I click one of the historyActions to go to that page. My entire application freezes up and crashes. How can I make it just go to the URL without crashing?

    Thanks for your help, I know these are n00bie problems, but I appreciate your help nonetheless!


  • Lifetime Qt Champion

    You are probably creating a loop

    Why are you creating numRecentHistory actions each time you call addToHistory ?



  • What would be a better way to do it?


  • Lifetime Qt Champion

    Like I said, follow the Recent File Example, it shows how to handle that



  • I have tried to follow that example, and based on it thats what I have so far.
    How is it creating a loop and how do I fix it?


  • Lifetime Qt Champion

    You're code doesn't reflect the example, you are creating each time numRecentHistory actions.

    The best way to see where the problem lies is to run your application through the debugger



  • As in 'debug' vs 'release' when i hit the run button?



  • Would having numRecentHistory outside of the function so it isn't created every time be better?


  • Lifetime Qt Champion

    As in use the button with a little bug on it with a debug build of your application



  • Okay now if I click on one one of the historyActions, nothing happens. It doesn't load the page, crash, or anything.

    Code:

    @void browseTab::addToHistory()
    {
    QString url = webView->url().toString();

    QString historyEntry = url;
    
    QString title = webView->title();
    
    QIcon icon = webView->icon();
    
    int numRecentHistory = 1;
    
    for (int i = 0; i < numRecentHistory; ++i)
    {
        QString text = tr("&%1").arg(title);
    
        historyAction = new QAction(this);
        historyAction->setText(text);
        historyAction->setData(historyEntry);
        historyAction->setIcon(webView->icon());
        historyAction->setIconVisibleInMenu(true);
        HistoryMenu->addAction(historyAction);
        connect(historyAction, SIGNAL(triggered()), SLOT(goToHistoryURL()));
    }
    

    }

    //determines which historyAction has been clicked, calls loadHistory().
    void browseTab::goToHistoryURL()
    {
    QAction *action = qobject_cast<QAction *>(sender());
    if (action)
    loadHistory(action->data().toString());
    }

    //sets the webView to the historyAction's url, called by goToHistoryURL().
    void browseTab::loadHistory(const QString &name)
    {
    webView->setUrl(QUrl(QString(name)));
    }
    @



  • Okay I restarted Qt and now it crashes again like it has been. I ran the debugger and it seemed to have an issue with the following code:
    @loadHistory(action->data().toString());@

    How can I fix this?
    Thanks! I appreciate your help SGaist!



  • Sorry to resurrect the thread,

    I am still having trouble with my application crashing when I click one of the historyActions, I have read the examples provided, and I still don't understand why it crashes. Could someone please help me?



  • If it crashes, the first thing to do is to get out your debugger to figure out where it crashes.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.