I'm having difficulties to make a QMenuBar display a QMenu with a QAction under Mac OS X (Snow Leopard).
Here is the code I'm using for creating the menu:
void ClientWindow::setUpMenu ()
{
QMenu * file = menuBar()->addMenu("&File");
QAction * quit = new QAction("&Quit", this);
file->addAction(quit);
connect(quit, SIGNAL(triggered()), this, SLOT(quit()));
}
Here is the ClientWindow class interface:
class ClientWindow : public QMainWindow
{
public:
ClientWindow (QWidget * parent = 0);
void setUpMenu ();
};
And here is my main() method:
int main (int argc, char * argv[])
{
QApplication app(argc, argv);
ClientWindow window;
window.setUpMenu();
window.show();
return app.exec();
}
Any ideas why it wouldn't show up on the menu bar?
Thank you all.
I solved the problem.
It appears that there is one action called "Quit" already, which is part of the default application's menu (every Mac OS X GUI app has such menu). This causes my attempt to add another action called "Quit" to be ignored by either Qt or the Window Server.
Simply renaming the action to "Close" solved the problem.
Some menupoints are automatically mapped to the mac osx native menu:
see http://doc.trolltech.com/4.6/mac-differences.html#menu-bar
Related
I recently packaged my app for MAC Store and was rejected. Below is the message sent to me by review team. When i testing using development mode everything works fine but I can't picture where i am getting something wrong. Any idea would be appreciated. App was built using Electron.
Design Preamble
The user interface of your app is not consistent with the macOS Human
Interface Guidelines.
Specifically, we found that when the user closes the main application
window there is no menu item to re-open it.
Next Steps
It would be appropriate for the app to implement a Window menu that
lists the main window so it can be reopened, or provide similar
functionality in another menu item. macOS Human Interface Guidelines
state that "The menu bar [a]lways contains [a] Window menu".
Alternatively, if the application is a single-window app, it might be
appropriate to save data and quit the app when the main window is
closed.
For information on managing windows in macOS, please review the
following sections in Apple Human Interface Guidelines:
The Menu Bar and Its Menus
The Window Menu
The File Menu
Clicking in the Dock
Window Behavior
Please evaluate how you can
implement the appropriate changes, and resubmit your app for review.
The Problem is that after the Application is minimized by pressing the x button, there is no way for the user to open it again from the dock.
One way to fix this is to just terminate the Application when the x button is clicked.
I had the same issue and fixed it by adding this function in AppDelegate. This solution is for Swift 4.2
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
Now the Application terminates, when the x button is clicked.
If you are working with Xamarin, edit your AppDelegate.cs to create a menu to reopen the main window:
public class AppDelegate : FormsApplicationDelegate
{
NSWindow window;
public override NSWindow MainWindow
{
get
{
return window;
}
}
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;
var rect = new CoreGraphics.CGRect(100, 100, 1024, 768);
window = new NSWindow(rect, style, NSBackingStore.Buffered, false);
window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
private NSMenu MakeMainMenu()
{
// top bar app menu
NSMenu menubar = new NSMenu();
NSMenuItem appMenuItem = new NSMenuItem();
menubar.AddItem(appMenuItem);
NSMenu appMenu = new NSMenu();
appMenuItem.Submenu = appMenu;
// add separator
NSMenuItem separator = NSMenuItem.SeparatorItem;
appMenu.AddItem(separator);
// add open menu item
string openTitle = String.Format("Open {0}", "MyApp");
var openMenuItem = new NSMenuItem(openTitle, "o", delegate
{
// Get new window
window.MakeKeyAndOrderFront(this);
});
appMenu.AddItem(openMenuItem);
// add quit menu item
string quitTitle = String.Format("Quit {0}", "MyApp");
var quitMenuItem = new NSMenuItem(quitTitle, "q", delegate
{
NSApplication.SharedApplication.Terminate(menubar);
});
appMenu.AddItem(quitMenuItem);
return menubar;
}
public override void DidFinishLaunching(NSNotification notification)
{
// finally add menu
NSApplication.SharedApplication.MainMenu = MakeMainMenu();
// Insert code here to initialize your application
Forms.Init();
//Load Application
LoadApplication(new App());
//Did Finish Launching
base.DidFinishLaunching(notification);
}
public override void WillTerminate(NSNotification notification)
{
// Insert code here to tear down your application
}
}
If you are workwing with Cocoa do the same but in the specific language.
Reopen the window with this instruction:
[window makeKeyAndOrderFront:self];
For electron apps you can add this code to your index.js or main.js to resolve the issue:
app.on('window-all-closed', () => {
app.quit();
});
I'm using Qt 5.2 and trying to embed notepad.exe into a widget in my QApplication.
my code is:
HWND winHandle = ::FindWindowA(NULL, "Untitled - Notepad");
if(winHandle != NULL)
{
QWindow * window = QWindow::fromWinId((WId) winHandle);
QWidget * notepadWidget = QWidget::createWindowContainer(window);
notepadWidget ->setParent( ui->widget);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(notepadWidget);
ui->widget->setLayout(layout);
}
the notepad window is embedded beautifully into my application, but i lost the keyboard! i cannot type inside notepad. the mouse is working properly(i can select text, etc.)
anyone?
I am building a QML application that must work on Windows and Mac OS X. I want to manage the menus in QML so I started using the MenuBar component in my application. I am using a QQuickView in C++ to display my QML elements. My menus appear properly on Mac OS X but I get nothing displayed on Windows and no errors in the logs.
The documentation speaks about this component being linked to ApplicationWindow but as it was working fine on Mac OS I was hoping it would work the same anywhere.
Is there a way to fix this on Windows ?
It seems that QQuickView is not able to contain ApplicationWindow as a root object.
Have you tried to use QQmlApplicationEngine instead of QQuickView?
#include <QtGui/QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine("qml/untitled/main.qml");
QObject* root = engine.rootObjects().at(0);
static_cast<QWindow*>(root)->show();
return app.exec();
}
I faced with the same issue on Windows, and it helped me.
I had a look at the way this is done in the QML ApplicationWindow component and found a way to display my menu on Windows. The idea/hack is to use the property __contentItem of the MenuBar component and attach it to the root element. I also do this only if the menu is not native so that it works as it did before on Mac OS X.
TopMenu.qml
import QtQuick 2.1
import QtQuick.Controls 1.0
MenuBar {
Menu {
title: "Window"
MenuItem {
text: "SubMenu3"
shortcut: "Ctrl+s"
}
MenuItem {
text: "SubMenu2"
shortcut: "Ctrl+p"
}
MenuItem {
text: "Preferences"
shortcut: "Ctrl+,"
}
}
}
RootElement.qml
import QtQuick 2.1
Rectangle {
id: rootWindow
width: 400
height: 400
Item {
id: menuWrapper
anchors.fill: parent
TopMenu {
id: myTopMenu
}
states: State {
name: "hasMenuBar"
when: myTopMenu && !myTopMenu.__isNative
ParentChange {
target: myTopMenu.__contentItem
parent: rootWindow
}
PropertyChanges {
target: myTopMenu.__contentItem
x: 0
y: 0
width: menuWrapper.width
}
}
}
}
How can I get a Java 7 application to have its menu bar at the top of the screen (on a Mac) and also have correctly working keyboard shortcuts?
I have a Java application with a Swing user interface. Many menus have keyboard equivalents, which are essential.
There is very little that is system-dependent, but on Mac OS X the menu bar should appear at the top of the screen instead of on each window, so I set apple.laf.useScreenMenuBar.
This works fine on Java 6, but on Java 7 (out last week!) compiling and running the same code causes the keyboard shortcuts to carry out their menu actions twice. For example, in the attached code, Command ⌘ + O opens two file dialogues instead of one. (The other keyboard shortcuts also act twice, but you sometimes have to move windows to see that they did.)
The keyboard problem goes away if I don't set apple.laf.useScreenMenuBar, and that's what I'll do if I have to, but my Mac users will be displeased. I'd really like to have the menu bar in the right place and the keyboard shortcuts working.
System: Mac OS 10.7.3 (Lion) on a late-2010 MacBook Pro
Java 7:
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)
Java 6:
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3635)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode)
Where I've looked:
A discussion of why apple.laf.useScreenMenuBar should be gotten rid of
-- I'm all for it, but it doesn't seem to have happened.
A discussion about not using mrj.version to detect that you're on a Mac
-- not directly relevant, but sounded promising.
My apologies for the length of the attached code (148 lines), but my Swing coding is very old-fashioned. It should compile and run from the command line without any special flags or settings.
import javax.swing.*;
import java.awt.Toolkit;
import java.awt.*;
import java.awt.event.*;
/**
* Shows that using the single screen-top menu bar on a Mac with Java 7
* causes keyboard shortcuts to act twice.
*
* To see the problem(on a Mac -- running OS X 10.7.3 in my case):
* 1) compile on either Java 6 or Java 7
* 2) run on Java 7
* 3) give the command-O shortcut
* You will see two file dialogues.
*
* -- J. Clarke, May 2012
*/
public class MenuBug {
private static void go(String[] args) {
// Comment out the following line to fix the problem;
// leave it active to see the problem.
// It doesn't help to ...
// ... put the line into a static block.
// ... put the line right after the setLookAndFeel call.
// ... put the line before after the setLookAndFeel call.
System.setProperty("apple.laf.useScreenMenuBar", "true");
MainWindow mainWindow = new MainWindow();
}
public static void main(final String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
JOptionPane.showMessageDialog(null,
e + " while loading look and feel",
"MenuBug error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
go(args);
}
});
}
}
class MainWindow extends JFrame {
MainWindow() {
super ("Main Window");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener (new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
pack();
setSize(350,300);
setVisible(true);
}
private JMenuBar createMenuBar() {
JMenuBar mBar = new JMenuBar();
JMenu menu = new JMenu("File");
String[] menuItemNames = new String[] {"New", "Open...", "Other"};
for (int i = 0; i < menuItemNames.length; i++) {
String miName = menuItemNames[i];
JMenuItem mi = new JMenuItem(miName);
mi.setActionCommand(miName);
linkMenuItemToAction(mi);
menu.add(mi);
}
mBar.add(menu);
return mBar;
}
/**
* Create an Action for menuItem, and make sure the action and the menu
* item know about each other; where appropriate, add keyboard equivalents.
* #param menuItem The menu item to be linked to an action.
*/
private void linkMenuItemToAction(JMenuItem menuItem) {
final int META_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
Action a = null;
String miName = menuItem.getActionCommand();
if (miName.equals ("New")) {
a = new NewAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
META_MASK));
}
else if (miName.equals ("Open...")) {
a = new OpenAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
META_MASK));
}
else if (miName.equals ("Other")) {
a = new OtherAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
META_MASK));
}
menuItem.setEnabled(a.isEnabled());
menuItem.addActionListener(a);
}
private class NewAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
new MainWindow();
}
}
private void makeDialog() {
String dialogTitle = "Please choose a file to open";
FileDialog fileDialog = new FileDialog(this, dialogTitle,
FileDialog.LOAD);
fileDialog.setVisible(true);
String fileName = fileDialog.getFile();
}
private class OpenAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
makeDialog();
}
}
private class OtherAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,
"an example message",
"not really an error", JOptionPane.ERROR_MESSAGE);
}
}
}
I'm answering my own question -- sort of. As noted in the comments to the original, the trouble goes away with Java 1.7u10.
It looks like that this problem still exist but now it can be reproduced with fn + backSpace (delete) on mac with 1.7_21.
I used the same example as above just added text field. Select part of text in textfield and press delete (fn+backspace)
Change KeyStroke to "DELETE" in linkMenuItemToAction method
else if (miName.equals ("Other"))
{
a = new OtherAction();
menuItem.setAccelerator(KeyStroke.getKeyStroke("DELETE"));
}
and add this:
JTextField textField = new JTextField(10);
textField.setText("Long long long long long long long text");
add(textField, BorderLayout.PAGE_START);
to MainWindow constructor.
Is there a way to limit mouse pointer movement to a specific area in wxWidgets? I know there is an API function ClipCursor() in Windows, but is there a method in wxWidgets for all platforms?
No. There is no such function in wx by all i know. Start up a timer (say 50ms) checking the global mouse position. If the mouse is outside the region, then set it into again.
If you want to restrict the mouse for some certain reason, for example to make some sort of game, then you can capture the mouse (see wxWindow::CaptureMouse). You will get mouse events even if the pointer is outside your window. Then you could react to mouse-motion events and do the check for the position there, without a timer. Downside of this is that the mouse won't be able to be used somewhere else for other programs since they won't receive events.
wxWidgets manual states that OSX guidelines forbid the programs to set the mouse pointer to a certain position programmatically. That might contribute to the reason there is not much support for such stuff in wx, especially since wx tries really hard to be compatible to everything possible.
Small sample. Click on the button to restrict the mouse to area 0,0,100,100. Click somewhere to release it.
#include <wx/wx.h>
namespace sample {
class MyWin : public wxFrame {
public:
MyWin()
:wxFrame(0, wxID_ANY, wxT("haha title")) {
mRestricted = wxRect(0, 0, 100, 100);
mLast = mRestricted.GetTopLeft();
wxButton * button = new wxButton(this, wxID_ANY, wxT("click this"));
}
private:
void OnClicked(wxCommandEvent& event) {
if(!HasCapture()) {
CaptureMouse();
CheckPosition();
}
}
void OnMotion(wxMouseEvent& event) {
CheckPosition();
}
void OnLeft(wxMouseEvent& event) {
if(HasCapture())
ReleaseMouse();
}
void CheckPosition() {
wxPoint pos = wxGetMousePosition();
if(!mRestricted.Contains(pos)) {
pos = ScreenToClient(mLast);
WarpPointer(pos.x, pos.y);
} else {
mLast = pos;
}
}
wxRect mRestricted;
wxPoint mLast;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MyWin, wxFrame)
EVT_BUTTON(wxID_ANY, MyWin::OnClicked)
EVT_MOTION(MyWin::OnMotion)
EVT_LEFT_DOWN(MyWin::OnLeft)
END_EVENT_TABLE()
class MyApp : public wxApp {
virtual bool OnInit() {
MyWin * win = new MyWin;
win -> Show();
SetTopWindow(win);
return true;
}
};
} /* sample:: */
IMPLEMENT_APP(sample::MyApp)