Swing Actions direkt auf der JMenuBar

Status
Nicht offen für weitere Antworten.

KrokoDiehl

Top Contributor
Hallo zusammen.
In der Anwendung unserer Firma gibt es (ziemlich oft) Menüleisten mit Menüpunkten, die keine Submenüs haben, sprich wie Buttons (intern vom Typ Action) reagieren.
Da man auf eine JMenuBar nicht direkt Actions legen kann, ist meine Vorgehensweise bisher wie folgt:

- Es gibt "normale" Menüs, sprich ein JMenu welches als Submenüs einige Actions bekommt (völlig unproblematisch ;) )-
- Die Actions, die keine Submenüs haben, sollen direkt auf die Menüleiste. Bisher werden diese als JButton drauf gesetzt.

Das funktioniert im Grunde ganz gut, wenn man dem JButton noch ein paar Eigenschaften verpasst, sodass er wie ein normales JMenu aussieht (wie
Code:
setBorderPainted(false);
).

ABER ... dann kommen die Look&Feels ins Spiel, die z.B. andere MouseOver-Effekte haben oder die Breiten anders berechnen.
Es wäre nun schön, wenn ich diese JButton auf der Menüleiste noch so hinbekommen würde, dass sie sich entspr. dem Look&Feel auch verhalten und aussehen wie JMenus.

Kann mir hier jemand einen Hinweis geben / Hilfe leisten? Ich habe folgende Ansätze schon ausprobiert mit den jeweils genannten Ergebnissen. Vielleicht hat dazu jmd einen Korrekturvorschlag?


Folgende Dinge wurden schon probiert:

1) Direkt JMenuItem auf die JMenuBar legen:
Java:
myMenuBar.add( new JMenuItem(currentAction) );
Das geht zwar, aber die MenuItems sehen da sehr schräg aus, viel zu breit und Borders werden teilweise seltsam gezeichnet.

2) ActionListener an JMenu setzen:
Es wird direkt ein JMenu (ohne Submenüs) auf die Leiste gelegt und diesem Menü ein ActionListener verpasst. Mit dem dem Effekt, dass beim Klick auf das Menü nur ein kleines Eckchen zu sehen ist (leeres Popupmenü) und der eigene ActionListener gar nicht anspringt.

3) Dem JButton die MenuUI verpassen:
Man kann ja via
Code:
setUI()
das entsprechende UI vom Look&Feel setzen. Dies schien mir der erfolgreichste Ansatz, aber leider fruchtete etwas wie
Java:
myMenuButton.setUI(  UIManager.getUI(new JMenu()) );
// myMenuButton vom Typ JButton
nur in einer ClassCastException
Mit den UIs habe ich bisher nichts gemacht und weiß daher auch nicht sicher, wie ich damit umgehen muss, sprich ob es überhaupt möglich ist, nem JButton die UI von einem JMenu zu geben (immerhin erben beide von AbstractButton).

Also soweit mein Problem. Danke schonmal fürs Lesen und Nachdenken ;)
 

eRaaaa

Top Contributor
huhu,

ich hab zwar keine direkte lösung, aber eine frage/anmerkung :)
eine menubar, ist doch dafür vorgesehen, menüs ranzuhängen, wärs in eurem fall nicht vllt sinnvoller, die "buttons" so wie du sie nennst, vllt in eine toolbar o.ä. auszulagern?
denn der user erwartet ja, wenn er in der menubar etwas anklickt, dass sich ein menü öffnet, bei euch würde dann direkt eine aktion ausgeführt werden, was manche, mich würde das zumindestens, etwas verwirren würde.


oder den umweg gehen und vllt dann lieber ein menü mit nur einem eintrag.

so, das wollt ich einfach mal in den raum werfen, vllt sagt ja ein GUI guru auch dazu was :)
 

KrokoDiehl

Top Contributor
Ja da stimme ich dir zu: Unsere Menüleiste ist etwas unkonventionell, soll aber (leider!) so bleiben, da es bereits eine ältere Oberfläche gibt, die als Vorlage dient, und man keinem Benutzer zumuten will, dass er seine Gewohnheiten ändern muss.
 

Michael...

Top Contributor
Ich würde den Button lassen, denn wenn ich auf einen Menüeintrag in der MenüBar klicke erwarte ich, dass sich ein Untermenü öffnet. Und beim Button kann ich wenigstens erkennen, dass das mein Click eine direkte Konsequenz hat.

Ansonsten könnte man vielleicht mit einen MenuListener rumspielen, ob man da das Verhalten immitieren kann.
 

Ebenius

Top Contributor
Ich stimme auch zu, dass das nicht hübsch ist. Wenn Du aber an der Anforderung nicht vorbei kommst, sollte dies eine ganz hübsche Arbeitsgrundlage sein:
Java:
/* (@)JMenuBarButton.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius.swing;

import java.awt.*;

import javax.swing.*;
import javax.swing.border.Border;

/**
 * A JButton looking like a JMenu.
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 * @since Playground-3.8
 */
public class JMenuBarButton extends JButton {

  /** Serial version UID */
  private static final long serialVersionUID = 1L;
  // -------------------------------------------------------------------------
  // Instance fields
  // -------------------------------------------------------------------------

  private JMenu menu;
  private CellRendererPane rendererPane;

  // -------------------------------------------------------------------------
  // Constructors
  // -------------------------------------------------------------------------

  /** Creates a new {@code JMenuBarButton}. */
  public JMenuBarButton() {
    menu = new JMenu() {

      /** Serial version UID */
      private static final long serialVersionUID = 1L;

      @Override
      public boolean isTopLevelMenu() {
        return true;
      }

      @Override
      public void menuSelectionChanged(boolean isIncluded) {}

      @Override
      public void setPopupMenuVisible(boolean b) {}

      @Override
      public void setBorder(Border border) {
        super.setBorder(border);
      }

      @Override
      public void addNotify() {
        super.addNotify();
      }

      @Override
      public Container getParent() {
        Container p = super.getParent();
        if (p instanceof CellRendererPane) {
          p = p.getParent();
          if (p instanceof JMenuBarButton) {
            return p.getParent();
          }
        }
        return p;
      }
    };
    menu.setModel(new DefaultButtonModel());
    menu.setAction(getAction());
    menu.setText(getText());
    menu.setIcon(getIcon());
    menu.setMnemonic(getMnemonic());
    menu.setToolTipText(getToolTipText());
    menu.setBounds(0, 0, 0, 0);

    setOpaque(menu.isOpaque());
    setBorder(BorderFactory.createEmptyBorder());
    setLayout(new BorderLayout());
    setBorderPainted(false);

    add(rendererPane = new CellRendererPane(), BorderLayout.CENTER);
    rendererPane.add(menu);
  }

  // -------------------------------------------------------------------------
  // Tweak painting
  // -------------------------------------------------------------------------

  /**
   * Creates a new <code>JMenuBarButton</code> with an action.
   * 
   * @param a the action
   */
  public JMenuBarButton(Action a) {
    this();
    setAction(a);
  }

  /**
   * Creates a new <code>JMenuBarButton</code> with an icon.
   * 
   * @param icon the icon
   */
  public JMenuBarButton(Icon icon) {
    this();
    setIcon(icon);
  }

  /**
   * Creates a new <code>JMenuBarButton</code> with text and icon.
   * 
   * @param text the text
   * @param icon the icon
   */
  public JMenuBarButton(String text, Icon icon) {
    this();
    setText(text);
    setIcon(icon);
  }

  /**
   * Creates a new <code>JMenuBarButton</code> with a text.
   * 
   * @param text the text
   */
  public JMenuBarButton(String text) {
    this();
    setText(text);
  }

  // -------------------------------------------------------------------------
  // Custom painting
  // -------------------------------------------------------------------------

  @Override
  protected void paintBorder(Graphics g) {}

  @Override
  protected void paintChildren(Graphics g) {}

  @Override
  protected void paintComponent(Graphics g) {
// super.paintComponent(g);
    if (menu != null) {
      rendererPane.paintComponent(g, configureRendererComponent(), this, 0,
            0, getWidth(), getHeight(), true);
    }
  }

  private JMenu configureRendererComponent() {
    final ButtonModel menuModel = menu.getModel();
    final ButtonModel myModel = getModel();
    menuModel.setEnabled(myModel.isEnabled());
    menuModel.setPressed(myModel.isPressed());
    // Menu is selected if button is pressed
    menuModel.setSelected(myModel.isPressed());
    // Don't arm the model; SynthLFs don't like that
    // menuModel.setArmed(myModel.isArmed());
    menuModel.setRollover(myModel.isRollover());

    menu.setIcon(getIcon());
    menu.setDisabledIcon(getDisabledIcon());
    menu.setDisabledSelectedIcon(getDisabledSelectedIcon());
    menu.setSelectedIcon(getSelectedIcon());

    menu.setIconTextGap(getIconTextGap());
    menu.setText(getText());
    menu.setMnemonic(getMnemonic());
    menu.setDisplayedMnemonicIndex(getDisplayedMnemonicIndex());
    menu.setEnabled(isEnabled());
    menu.setComponentOrientation(getComponentOrientation());
    menu.setOpaque(isOpaque());
    return menu;
  }

  // -------------------------------------------------------------------------
  // Delegate Size getters to the menu
  // -------------------------------------------------------------------------

  @Override
  public Dimension getPreferredSize() {
    return menu != null
          ? configureRendererComponent().getPreferredSize()
          : super.getPreferredSize();
  }

  @Override
  public Dimension getMinimumSize() {
    return menu != null
          ? configureRendererComponent().getMinimumSize()
          : super.getMinimumSize();
  }

  @Override
  public Dimension getMaximumSize() {
    return menu != null
          ? configureRendererComponent().getMaximumSize()
          : super.getMaximumSize();
  }

  // -------------------------------------------------------------------------
  // Update the menu UI as well
  // -------------------------------------------------------------------------

  @Override
  public void updateUI() {
    super.updateUI();
    if (menu != null) {
      menu.updateUI();
    }
  }
}
Funktioniert augenscheinlich mit Metal-LAF, Nimbus-LAF (Snyth), CDE/Motif-LAF und GTK+-LAF. Hab kein Windows und keinen Mac zum Testen.

Happy Hacking!
Ebenius
 

KrokoDiehl

Top Contributor
Sehr genial Ebenius!
Ich habe es mit noch einigen weiteren L&Fs getestet und die Nebeneffekte meiner Lösung sind damit behoben:
- keine unterschiedlichen Menübreiten mehr
- kein L&F-eigenes Aussehen für diese JButtons im Unterschied zu den JMenus
- Windows & Linux sind hier gleich

Einzig beim com.birosoft.liquid.LiquidLookAndFeel haben die JMenus noch einen MouseOver-Effekt. An dieser Stelle werde ich noch etwas probieren, aber das ist vernachlässigbar (wir wissen ja selbst noch nicht, welche L&Fs überhaupt benutzt werden sollen).

Also vielen Dank für die Lösung. Muss ich dir nun einen Teil meines Gehalts überweisen? ;)
 

Ebenius

Top Contributor
Einzig beim com.birosoft.liquid.LiquidLookAndFeel haben die JMenus noch einen MouseOver-Effekt. An dieser Stelle werde ich noch etwas probieren, aber das ist vernachlässigbar (wir wissen ja selbst noch nicht, welche L&Fs überhaupt benutzt werden sollen).
Eventuell musst Du noch dem Button sagen, er soll RollOverEnabled vom menu-Feld übernehmen.

Also vielen Dank für die Lösung. Muss ich dir nun einen Teil meines Gehalts überweisen? ;)
Wie jetzt, einen Teil? ;-)

Ebenius
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Z Swing Java Actions AWT, Swing, JavaFX & SWT 4
Z Swing Actions Designfrage AWT, Swing, JavaFX & SWT 2
H Ein Button - zwei Actions AWT, Swing, JavaFX & SWT 3
D Swing Storage von / Zugriff auf und durch Actions AWT, Swing, JavaFX & SWT 5
S Seltsames Problem - manchmal enthaelt die ActionMap eine JTextArea keine Actions. AWT, Swing, JavaFX & SWT 4
Daniel_L Actionmap - Standard-Actions? AWT, Swing, JavaFX & SWT 2
F Problem mit Actions, TextComponents und Focus AWT, Swing, JavaFX & SWT 2
F Wie gebe ich Parameter zwischen Actions weiter? AWT, Swing, JavaFX & SWT 2
R Button actions mit Tastatur ausführen AWT, Swing, JavaFX & SWT 6
F AWT awt KeyEvent - Zeichen direkt nach Eingabe löschen AWT, Swing, JavaFX & SWT 2
S JDialog direkt über dem MainFrame aufpoppen lassen AWT, Swing, JavaFX & SWT 2
B Bild direkt im Quelltext erstellen AWT, Swing, JavaFX & SWT 14
P Bild DIREKT in JFrame einfügen AWT, Swing, JavaFX & SWT 8
N JTable direkt editierenund in Datenbanken speichern AWT, Swing, JavaFX & SWT 5
R paintComponent direkt bei actionPerformed aufrufen AWT, Swing, JavaFX & SWT 2
R Direkt in Puffer schreiben AWT, Swing, JavaFX & SWT 7
T Elemente werden nicht direkt angezeigt AWT, Swing, JavaFX & SWT 3
S Warum nicht direkt auf JFrame Komponenten adden? AWT, Swing, JavaFX & SWT 2
A Drag'n Drop: Absender direkt ansprechen? AWT, Swing, JavaFX & SWT 2
S Direkt auf den Desktop zeichnen? AWT, Swing, JavaFX & SWT 17
S JButtons in einem JPanel erscheinen nicht direkt AWT, Swing, JavaFX & SWT 7
G Bild direkt aus Datenbank anzeigen lassen AWT, Swing, JavaFX & SWT 14
C JMenuBar AWT, Swing, JavaFX & SWT 6
K Event Handling Über JMenuBar die diversen Panels anzeigen AWT, Swing, JavaFX & SWT 10
J Swing JMenuItem blockiert JMenuBar AWT, Swing, JavaFX & SWT 2
S JMenuBar bei sichtbarer JGlassPane AWT, Swing, JavaFX & SWT 1
R JMenuBar.setFont tut nix ? AWT, Swing, JavaFX & SWT 1
I Swing JMenuBar auch unten am JFrame? AWT, Swing, JavaFX & SWT 2
A Swing JMenuBar updaten AWT, Swing, JavaFX & SWT 2
kaoZ Swing JMenuBar, Preferences, Properties... und viele andere lustige Dinge (Best Practice) AWT, Swing, JavaFX & SWT 15
Q Designfrage zur JMenuBar AWT, Swing, JavaFX & SWT 6
S JMenuBar wiederverwenden und Eventhandling anpassen AWT, Swing, JavaFX & SWT 4
B Swing JMenuBar unten in der Frame setzen? AWT, Swing, JavaFX & SWT 15
Q Fragen zur JMenuBar & Co. AWT, Swing, JavaFX & SWT 3
M Über eine JMenuBar überprüfen ob ein JCheckBoxMenuItem selectiert ist. AWT, Swing, JavaFX & SWT 4
M JMenuBar, JMenu, JMenuItem wird nicht angezeigt AWT, Swing, JavaFX & SWT 16
G Swing JMenuBar zu weit links und oben dargestellt AWT, Swing, JavaFX & SWT 5
B Swing Dynamische JMenuBar AWT, Swing, JavaFX & SWT 2
J JMenuBar ist geaddet, aber nicht im Frame. Wo ist der Fehler? (inkl. Code) AWT, Swing, JavaFX & SWT 2
D JMenuBar - CardLayout (Klasse anzeigen) AWT, Swing, JavaFX & SWT 3
S JMenuBar Frame Abstand AWT, Swing, JavaFX & SWT 3
H jMenuBar AWT, Swing, JavaFX & SWT 13
NR_EIGHT Swing Probleme mit JMenuBar AWT, Swing, JavaFX & SWT 6
M JMenuBar im Applet und paint AWT, Swing, JavaFX & SWT 9
Madlip JMenuBar in JFrame AWT, Swing, JavaFX & SWT 5
B JFrame / JMenuBar => Anfängerprobleme AWT, Swing, JavaFX & SWT 2
R JMenuBar AWT, Swing, JavaFX & SWT 2
S JMenuBar nach 1. Klick deselectieren AWT, Swing, JavaFX & SWT 6
Z JMenuBar wird nicht in JFrame angezeigt AWT, Swing, JavaFX & SWT 2
N JMenuBar verschwindet nicht nach ComponentEvent AWT, Swing, JavaFX & SWT 6
C JMenuBar aktualisieren? AWT, Swing, JavaFX & SWT 2
A Doppelte JMenuBar AWT, Swing, JavaFX & SWT 2
X NullPointerException beim Einfügen einer JMenuBar AWT, Swing, JavaFX & SWT 4
C JMenuBar im JFrame abgehackt AWT, Swing, JavaFX & SWT 7
J Swing JFrame mit JMenuBar, allerdings ohne Erfolg AWT, Swing, JavaFX & SWT 10
K Look&Feel von JMenuBar und Subkomponenten anpassen AWT, Swing, JavaFX & SWT 6
C JMenuBar linksbündig AWT, Swing, JavaFX & SWT 6
C Größe JMenuBar AWT, Swing, JavaFX & SWT 5
L Swing Kommunikation zwischen JMenuBar und anderen Componenten AWT, Swing, JavaFX & SWT 2
Developer_X Swing JMenuBar Layout AWT, Swing, JavaFX & SWT 2
kniffel JMenuBar aus anderer Klasse AWT, Swing, JavaFX & SWT 10
G Dynamische JMenuBar AWT, Swing, JavaFX & SWT 2
G JMenuBar verschmälern AWT, Swing, JavaFX & SWT 2
M ALT shortcut für JMenuBar deaktivieren AWT, Swing, JavaFX & SWT 3
X JMenuBar überlappt von JPanel :( AWT, Swing, JavaFX & SWT 7
M4nuel Warum überlagert JDesktopPane mein JMenuBar? AWT, Swing, JavaFX & SWT 5
G StatusBar Optik wie JMenuBar; GUI-Erzeugung delegieren AWT, Swing, JavaFX & SWT 2
J JMenuBar in Frame einbauen AWT, Swing, JavaFX & SWT 6
D Canvas über JMenuBar AWT, Swing, JavaFX & SWT 7
P JMenuBar und JToolBar Anzeige Probleme AWT, Swing, JavaFX & SWT 5
C JLabel in JMenuBar frei platzieren AWT, Swing, JavaFX & SWT 2
B JMenubar AWT, Swing, JavaFX & SWT 5
Chris_1980 Makierungsfarbe bei JMenuBar ändern AWT, Swing, JavaFX & SWT 5
L Problem mit JMenuBar AWT, Swing, JavaFX & SWT 5
F JTextField rechts in der JMenuBar AWT, Swing, JavaFX & SWT 4
A gezeichnete Linie verschwindet, wenn ich JMenuBar öffne AWT, Swing, JavaFX & SWT 2
I JMenuBar - Menüs sortieren AWT, Swing, JavaFX & SWT 2
S JMenuBar mit Action belegen! AWT, Swing, JavaFX & SWT 5
M JMenuBar AWT, Swing, JavaFX & SWT 7
B JMenuBar sowie Buttons nach repaint auf JPanel AWT, Swing, JavaFX & SWT 2
T JMenuBar ausblenden lassen aber Hotkeys sollen erhalten sein AWT, Swing, JavaFX & SWT 2
S JMenuBar + update AWT, Swing, JavaFX & SWT 3
M JMenuBar - JMenu mit Tastenkombination aufrufen / anzeigen AWT, Swing, JavaFX & SWT 8
T JMenuBar zweizeilig AWT, Swing, JavaFX & SWT 2
A JMenuBar + paint (Image) AWT, Swing, JavaFX & SWT 6
M JmenuBar wird net angezeigt :( AWT, Swing, JavaFX & SWT 6
U komplette JMenuBar deaktivieren? AWT, Swing, JavaFX & SWT 4
S Mausklick reagiert nicht im JMenuBar AWT, Swing, JavaFX & SWT 4
A JMenuBar verschieben. AWT, Swing, JavaFX & SWT 4
T JMenuBar wird nicht richtig angezeigt AWT, Swing, JavaFX & SWT 5
H JFrame, JMenuBar, ScrollBar AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben