如何实现模态来覆盖底层框架的一部分



我发现,当人们希望提出一个只阻塞JFrame的一部分的模态时,这就是常规范式的崩溃之处
一次尝试考虑一下这个例子——类似于桌面。一个内容窗格,其一侧有一个"应用程序窗口区域"和一个"按钮栏"。诀窍是弹出一个对话框,阻止应用程序窗口区,但不阻止按钮栏。

如果我要为无模式对话框实现模态,我必须做些什么才能捕捉到鼠标在底层内容窗格的给定维度上的活动(有问题的对话框的父级?),从而阻止用户访问它?

我唯一能想到的另一个考虑是隐藏一个"应用程序窗口"弹出的对话框,而不是另一个。我必须确保在切换应用程序窗口时隐藏对话框。

或者还有什么特别的需要考虑的吗?我知道,当点击被阻止的窗口时,模式对话框闪烁的方式也是一个很好的效果。

我已经产生了一个我认为可以使用的结果。标题栏的情况很有趣,但我想也可以被吸引,但我希望最终有一个没有标题栏的窗口。

我有一个类"AppFrame"子类JFrame,在下面的这些片段中(这只是测试代码),我使用AppFrame对象作为所有创建和侦听的东西的侦听器

当对话框打开时,类布尔值"isDialogued"被设置为true(在其WindowClosed事件中关闭,并作为其结束方式关闭)。

我捕捉到了以下事件,并检查了窗口顶部是否有对话框,以将焦点重定向到当时的对话框。鼠标按下并单击应用程序面板,应用程序面板上的ActionEvent to(the)按钮(所有可点击的控件都需要这个钩子),WindowActivated和WindowClosed事件。

"appPanels[]"是一个面板数组,每个面板都有自己的"应用程序窗口"。然后,有一个"appBarPanel"面板位于右侧(JFrame的contentPane BorderLayout上的EAST)。appPanels[0]是一个带有按钮("popupButton")的面板,它启动一个无模式的JDialog,在类中被引用为"对话框"。

当通过应用程序栏上的5个按钮(actionPerformed)切换卡片时,对话框将消失。当对话框在应用程序窗口区域之外,并且仍然通过单击应用程序栏按钮来隐藏和显示时,这有点酷。应用程序窗口区域似乎已被有效模式阻止。

@Override
public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    System.out.println("Action performed: "+source.getClass().getName());
    // App Bar
    for(int i=0; i<5; i++) {
        if(source == buttons[i]) {
            // card change
            if(i != cardSelected) {
                // Toolkit.getDefaultToolkit().beep();
                cardLayout.show(cardPanel, Integer.toString(i));
                cardSelected = i;
            }
            if(isDialogued) {
                // There is a dialog box right now (would be over card 0)
                if(i==0) {
                    dialog.setVisible(true);
                    dialog.toFront();
                } else {
                    dialog.setVisible(false);
                }
            }
            return;
        }
    }
    // currently blocking with a modeless on top
    if(isDialogued) {
        if(source != dialog) // dialog shares this event handler
            dialog.toFront();
        return;
    } else {
        if(source == popupButton) {
            isDialogued = true;
            dialog = new JDialog(this, "Pop-Up Dialog");
            dialog.setLayout(new FlowLayout(FlowLayout.CENTER));
            dialog.setSize(500, 120);
            dialog.setBackground(appBackColor);
            JLabel l = new JLabel("hello from app window 0");
            l.setHorizontalAlignment(JLabel.CENTER);
            dialog.getContentPane().add(l); 
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.addWindowListener(this);
            // dialog.setEnabled(true);
            dialog.setLocationRelativeTo(null);
            dialog.setVisible(true);
            return;
        }
    }       
}
@Override
public void windowActivated(WindowEvent e) {
    String s = "windowActivated() ";
    if(isDialogued) {
        s = s + "isDialogued ";
        if(e.getSource() != dialog)
            dialog.toFront();
    }
    System.out.println(s + e.getSource().getClass().getName());
}
@Override
public void windowClosed(WindowEvent e) {
    if(e.getSource() == dialog)
        isDialogued = false;
}
private void mouseDialogCheck(MouseEvent arg0, String s) {
    if(isDialogued) {
        s = s + "isDialogued ";
        s = s + arg0.getSource();
        // 
        if(arg0.getSource() == appPanels[0])
            dialog.toFront();
    }
    System.out.println(s);
}
@Override
public void mouseClicked(MouseEvent arg0) {
    String s = "mouseClicked() ";
    mouseDialogCheck(arg0, s);
}
@Override
public void mousePressed(MouseEvent arg0) {
    String s = "mousePressed() ";
    mouseDialogCheck(arg0, s);
}

第二种方法:我已经测试过了。这个解决方案似乎有三种方法可以解决这个问题,我称之为三帧
1) 仅全屏显示。(这符合我的需要)
2) 未装饰或不可移动且不可调整的窗口

3) 使用代码在向后拖动时移动3帧(可能很难看)

方法:制作3个JFrame。它们都没有装饰。第一个是背部框架,它得到了完整的尺寸。然后,在一个JFrame之上创建另外两个JFrames,覆盖它们的空间份额(沿途设置大小和位置)。

我们将其中一个较小的框架称为应用程序框架,另一个称为应用栏框架(实际上就像工具栏)。当在应用程序框架顶部制作JDialog时,为了不阻塞应用程序栏框架,请使用制作它们

new JDialog(appFrame, "Pop-Up", Dialog.ModalityType.DOCUMENT_MODAL);

否则,它们将阻塞所有帧。以这种方式使用DOCUMENT_MODAL似乎对我有效。当进入应用程序栏时,唯一的其他问题是重叠的对话框,但这只是一个保持最前面窗口的地方——应用程序栏,而不是任何对话框下面的所有应用程序窗口。

最新更新