Qt Mac (Re)move "Special Characters..." action in Edit menu - qt

I am developing an application in Qt that rebuilds its menus very often. However, when we call clear(), and re-add the actions that we want in the menu, "Special Characters..." appears to remain in the menu. Is there any way to remove, or move this action to the bottom of the QMenu?
Here is the code that rebuilds the menu:
void MainWindow::initMenus(Tab* tab)
{
menuBar()->clear();
menuFile->clear();
menuEdit->clear();
menuSettings->clear();
menuHelp->clear();
ui_toolBar->clear();
menuBar()->addMenu(menuFile);
menuBar()->addMenu(menuEdit);
menuFile->addAction(actionNew);
menuFile->addAction(actionOpen);
if(tab) tab->addActionsFile(menuFile);
menuFile->addSeparator();
menuFile->addAction(actionNext);
menuFile->addAction(actionPrevious);
menuFile->addAction(actionClose);
menuFile->addSeparator();
menuFile->addAction(actionQuit);
if(tab) {
tab->addActionsEdit(menuEdit);
menuEdit->addSeparator();
tab->addActionsHelp(menuHelp);
menuHelp->addSeparator();
}
menuEdit->addAction(actionEditor_Settings);
menuHelp->addSeparator();
menuHelp->addAction(actionAbout);
if(tab) tab->addOtherActions(menuBar());
menuBar()->addMenu(menuHelp);
ui_toolBar->addAction(actionNew);
ui_toolBar->addAction(actionOpen);
if(tab) tab->addToolbarActions(ui_toolBar);
}
It is supplied a tab, which can add its own actions to the menu as well using those functions.

This is a feature of Mac OS X that isn't easily disabled. You'll notice that nearly every application on Mac OS has it. It's automatically added to the Edit menu by the OS to allow the input of international characters.
It seems from your question, but isn't quite clear, that when you initially create the Edit menu, the Special Characters... menu item is initially the last menu item, but becomes the first menu item once editMenu->clear() has been called. One route you could go is instead of clear()ing the menus, you can delete the menus and recreate them completely. Your edit menu looks pretty static, though. Maybe it doesn't have to be recreated at all.
Now, that said, if you're really sure you need to get rid of this menu item, there are a couple of ways to accomplish that.
The first, and least desirable one is to simply not have an "Edit" menu. If there's no menu titled "Edit", Mac OS will not add a "Special Characters" menu item.
The second method requires a little platform specific Objective-C code. Obviously, this should only be built into your project on Mac OS.
MenuDeleter.m:
#include <Foundation/NSUserDefaults.h>
void deleteSpecialCharacters()
{
[[NSUserDefaults standardUserDefaults]
setBool:YES forKey:#"NSDisabledCharacterPaletteMenuItem"];
}
MenuDeleter.h
#ifndef MENUDELETER_H_
#define MENUDELETER_H_
void deleteSpecialCharacters();
#endif
And finally, in main.cpp:
#include <QApplicaiton>
#include "MenuDeleter.h"
int main(int argc, char **argv)
{
#ifdef Q_OS_MAC
deleteSpecialCharacters();
#endif
QApplication app(argc, argv);
....
return app.exec();
}
So that's how to make it go away completely. But the question is, do you really want to prevent the user from being able to input special characters into your app?

This answer may be more applicable to a COCOA OSX app, but I was able to remove these menu items in Objective-C by getting an NSMenu handle to the Edit Menu itself in the applicationDidFinishLaunching function , looping through the NSMenuItems in the itemArray and removing them by calling removeItem.

Related

Qt shortcut for custom context menu

I have been reading though a couple of examples and post but I just cannot figure out how to add a shortcut to my custom context menu. My GUI has several elements. One of them is a treeView. For the elements in my treeView I would like to have a custom context menu.
My first approach was according to this tutorial here. The context menu itself worked but the shortcuts cannot work if you create the actin within the show function.
So my second approach was according to this tutorial. But still my shortcuts do not work and if I use the context menu all actions are called twice...
Since I did not find a tutorial or code example, which matches my case, I hope that someone here can explain to me how this is correctly done in theory. Adding a shortcut to an action for a custom context menu.
Where do I have to declare my action?
What needs to be the parent of the action?
On which widget do I need to call addAction?
Thanks for any hints.
Another way is to add your action also to the parent widget (or main window widget). As mentioned in this reply, adding the same action to multiple widgets is fine and it's the way QActions are supposed to be used.
Example with custom HtmlBrowser class deriving from QTextBrowser:
Ctrl+U shortcut works for this code:
HtmlBrowser::HtmlBrowser(QWidget * parent) : QTextBrowser(parent)
{
viewSourceAct = new QAction(tr("View/hide HTML so&urce"), this);
viewSourceAct->setShortcut(tr("Ctrl+U"));
viewSourceAct->setCheckable(true);
parent->addAction(viewSourceAct);
connect(viewSourceAct, &QAction::triggered, this, &HtmlBrowser::viewSourceToggle);
}
and Ctrl+U shortcut does not work with this code (same as above, but without parent->AddAction(...)):
HtmlBrowser::HtmlBrowser(QWidget * parent) : QTextBrowser(parent)
{
viewSourceAct = new QAction(tr("View/hide HTML so&urce"), this);
viewSourceAct->setShortcut(tr("Ctrl+U"));
viewSourceAct->setCheckable(true);
connect(viewSourceAct, &QAction::triggered, this, &HtmlBrowser::viewSourceToggle);
}
Curiously, parent in this case is another widget (tab widget), not MainWindow. Still, adding parent->addAction() helps. And, unlike your suggested answer, it works even when connecting action to simple methods, without slots. Works for me in Qt 5.15.0. Not quite sure why it works, though. Perhaps, the widget the action is added to must be permanent for shortcuts to work? Looks like a bug in Qt.
Thanks to Scheff's hint I got it working. I do not now if this is really the correct way but this works for me.
The action needs to be declared in the constructor of your GUI class (e.g. MainWindow):
actionDel = new QAction(tr("delete"), this);
actionDel->setShortcut(QKeySequence(Qt::Key_Delete));
connect(actionDel, SIGNAL(triggered()), this, SLOT(actionDel_triggered()));
The triggered signal needs to be connected to a slot. Hint: if you create the slot do not use on_ACTIONNAME_triggered, this will interfere with the designer and cause a connection error.
Next add the action to a custom menu
fileContextMenu = new QMenu(this);
fileContextMenu->addAction(actionDel);
And to the widget
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDirContextMenu(QPoint)));
ui->treeView->addAction(actionDel);
All in the constructor of your GUI class.
To show the context menu use the following code in slot used in the above connect:
QModelIndex index=ui->treeView->indexAt(pos);
// Here you can modify the menu e.g. disabling certain actions
QAction* selectedItem = fileContextMenu->exec(ui->treeView->viewport()->mapToGlobal(pos));
If you do not have a slot for an action, the action can be also handled in the context menu slot, but this does not work with shortcuts!
if(selectedItem == actionOpen){
on_treeView_doubleClicked(index);
}

Qt Form and main.cpp communication

i have a Qt project with mainwindow (GUI Application)
how can i communicate with my main via my form?
for example
increase variable (which there's in my main) while button a click in my form
i have make a project in C which its in console application. works fine, and now i make another project which contains ui form with same code. and i want to make communication between form and main function
You can use the Qt signal/slot functionality.
Example:
// on mainwindow.cpp. Delcare onButtonClicked as a slot() on the header
void onButtonClicked()
{
++myVar;
}
connect(myButton, SIGNAL(clicked()), this, SLOT(onButtonClicked());
Reference docs.

Which qt widget should I use for message display?

The QStatusBar has just one line each time and I cannot track the history or save the history in a log file.
So I want to have a dock widget in my mainwindow that is able to display the messages I need in a multi-line way and auto-scrolling way and then automatically saved to a log file.
My question is how to do this in Qt?
If what you are looking for is something similar to the "Application Output" pane of QtCreator, then a simple QPlainTextEdit can do the job. You can call QPlainTextEdit::setReadOnly(true) if you don't want the user to be able to edit its content (i.e. only your application can write to it).
If you want auto-scrolling and automatically saving to a log file, you will need to subclass it though. Here's a little something to get you started:
#include <QCoreApplication>
class MyLogWindow : public QPlainTextEdit
{
Q_OBJECT
/* snip */
public:
void appendMessage(const QString& text);
private:
QFile m_logFile;
};
void MyLogWindow::appendMessage(const QString& text)
{
this->appendPlainText(text); // Adds the message to the widget
this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()); // Scrolls to the bottom
m_logFile.write(text); // Logs to file
// optional if you want to see the changes
// after appendPlainText() immediately
// useful if you use this->appendMessage() in a loop
QCoreApplication::processEvents();
}
I leave it to you to deal with the boilerplate (opening and closing the file, dealing with newlines, etc.).
Now, simply put an instance of MyLogWindow in a dock in your QMainWindow, and call MyLogWindow::appendMessage() every time you need to log something to have it displayed, scrolled and saved automatically.

Program crashes with WebKit Previewer example with on_textEdit_textChanged()

I recreated the example of a webkit that displays the content of a textEdit containing HTML: http://qt-project.org/doc/qt-4.8/webkit-previewer.html
I changed it so rather than the webkit HTML being changed upon clicking the button, it's changed upon the text in the textEdit being changed:
// changed when button is click. Works fine.
void Previewer::on_previewButton_clicked()
{
// Update the contents in web viewer
QString text = htmlTextEdit->toPlainText();
webView->setHtml(text);
}
// change when text is changed. Crashes.
void Previewer::on_htmlTextEdit_textChanged()
{
// Update the contents in web viewer
QString text = "<html><body><h1>No crash!</h1></body></html>";
webView->setHtml(text);
}
This causes the program to crash as soon as it starts. I altered the program to run the function only a bit later (I thought maybe something needed to be initialized) but it still crashed once it reached the textChanged function. Why is it crashing? How can I fix this?
Your program is entering an infinite loop because, in the example, there's a connection between the webView's loadFinished(bool) signal and the text/html editor's updateTextEdit() slot.
Basically, editing the HTML causes the page to load again, which causes an update to the editor, which causes the page to load again, so on and so forth.
A quick way I solved this was to add a static bool flag to the updateTextEdit SLOT/function that only allows it to run once.
void MainWindow::updateTextEdit()
{
static bool once = false;
if (once) {
return;
}
once = true;
QWebFrame *mainFrame = centralWidget->webView->page()->mainFrame();
QString frameText = mainFrame->toHtml();
centralWidget->plainTextEdit->setPlainText(frameText);
}
Doing this worked for me, but your version might work differently than mine. I followed the example closely, but added an htmlchanged() slot to the previewer class, and made the connection like so:
connect(centralWidget->plainTextEdit, SIGNAL(textChanged()), centralWidget, SLOT(html_changed()));
Also, I'm no expert, but I'm pretty sure this is not the best way to get around this, and I assume that updateTextEdit() needs to run more than once. It'll work for the time being, though.

Qt-Right click mouseReleaseEvents aren't caught by eventfilter,other events though are caught

My application consists of a WebView widget. A mouse click on the widget is not handled by the mousePressEvent() of my application, but by the WebView widget. So, I installed an event filter to receive the events. Now, I get notified of all events, except the mouseReleaseEvent for the right click (Everything works fine for left clicks and mousePressEvent for the right click is also getting registered). I guess it has got something to do with context events getting generated by right clicks (a pop-up menu gets generated). But since I am using a filter, the event should first be sent to me. The following is the code for the event filter
in Jambi, but I hope I can modify an answer given in Qt for Jambi.
public boolean eventFilter(QObject o,QEvent event)
{
if (event.type()==QEvent.Type.MouseButtonPress) // One can call the mousePressEvent() functions from here,which can do this work but speed
{
if (((QMouseEvent)event).button()==Qt.MouseButton.LeftButton)
{
mousebuttontype=1;
clickedorpressed=1;
}
else
if (((QMouseEvent)event).button()==Qt.MouseButton.RightButton)
{
mousebuttontype=2;
System.out.println("right");
}
t1=QTime.currentTime();
t1.start();
}
else
if (event.type()==QEvent.Type.MouseButtonRelease)
{
if (t1.elapsed()>900)
{
switch(mousebuttontype)
{
case 1: browser.back();
break;
case 2: browser.forward();
break;
}
}System.out.println("choda");
}
return false;
}
MY BASIC AIM IS GETTING THE TIME INTERVAL FOR WHICH THE RIGHT CLICK WAS PRESSED. ANY WORKAROUND ?
Some digging around certainly seems to suggest that there may be no right-mouse release event being generated if that is the trigger for a context menu on your particular system. These are conveyed as a QContextMenuEvent.
This Qt Labs post hints about this too.
A work around may be tricky if it is system dependent. Have you tried overriding event() in the QApplication class to see if the event comes through there? Some events don't necessarily get to the children but everything goes through QApplication::event().
Another option for you is, subclass Qwebview and override mouseReleaseEvent event
I've found a fix for this that I dont think will be system dependent.
My particular case was using mouseReleaseEvent in order to catch the events, and use them myself. I didn't get these events.
On all child widgets of the widget that I want to handle the event, I added to the class definition:
protected:
void mouseReleaseEvent(QMouseEvent *event) {event->ignore();}
This overrides the default implementation for context menu's, and sends the mouseReleaseEvent back up the parent chain like it would for other mousebuttons.
http://doc.qt.io/qt-5/qevent.html#ignore
This shows that it will probably propagate to the parent widget. As the link indicates, this fixed it for me at Qt 5.9, but I think it should work for virtually all version.
(I am aware this question is literally 7 years old, but it doesn't contain the fix that I think would be the best fix, and shows up as result 2 on google(qt not getting mouse release event on rightclick). So I think it deserves an up to date answer.)
Without going in to broader implementation explanations, the core problem I needed to solve related to this issue was that I needed to know if a context menu swallowed the right-click so I could ensure some custom state was handled properly. The simplest workaround I was able to find was to implement contextMenuEvent, which gets called after mousePressEvent, to detect if the event was accepted (a context menu was opened somewhere in my QGraphicsScene/Items). Here is a minimal example in Python to demonstrate how the event state might be used:
def contextMenuEvent(self, event):
event.setAccepted(False)
super(MyGraphicsView, self).contextMenuEvent(event)
self.__context_menu_used = event.isAccepted()
Note you can also skip running the the base class contextMenuEvent entirely to block the scene/items from opening a context menu. This is handy if you want to do 3D-DCC-like alt-RMB-zooming without accidentally opening a context menu, e.g.:
def contextMenuEvent(self, event):
# Block context menus if alt is held down
if event.modifiers() & QtCore.Qt.AltModifier:
return
event.setAccepted(False)
super(MyGraphicsView, self).contextMenuEvent(event)
self.__context_menu_used = event.isAccepted()

Resources