简体   繁体   English

如何使自定义框架正确重绘?

[英]How do I make my custom frame re-paint properly?

I am trying to create my own custom GUI toolkit based on swing as a bit of a side project. 我正在尝试创建一个基于Swing的自定义GUI工具包,这只是一个副项目。 My problem is this: I have created a frame with exit and minimize buttons however when I use the minimize button and maximise again, the window is not in the correct format. 我的问题是:我创建了一个带有退出和最小化按钮的框架,但是当我使用最小化按钮并再次最大化时,窗口的格式不正确。 Here is my code for the frame class. 这是我的框架类代码。

package com.SMS.GUI;

import java.awt.Color;
import java.awt.Frame;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseListener;


/**
 *
 * @author Marc
 */
final class SMSFrame extends JFrame implements MouseListener{

GUIButton minimizeButton, exitButton;
JPanel titleBar;

SMSFrame(int width, int height){
    setResizable(false);
    setUndecorated(true);
    setSize(width,height);
    getContentPane().setBackground(Color.decode("#8e44ad"));
    setVisible(true);

    minimizeButton = new GUIButton((width-100),0,50,50,"#1abc9c");
    exitButton = new GUIButton((width-50), 0, 50, 50, "#d35400");
    titleBar = new JPanel();

    titleBar.setBackground(Color.decode("#2c3e50"));
    titleBar.setBounds(0, 0, width, 50);


    minimizeButton.addMouseListener(this);
    exitButton.addMouseListener(this);


    add(titleBar);
    titleBar.add(exitButton);
    titleBar.add(minimizeButton);

}


@Override
public void mouseClicked(MouseEvent e) {
}

@Override
public void mousePressed(MouseEvent e) {
    if(e.getSource() == exitButton){
        exitButton.setBackground(Color.decode("#c0392b"));
    }

    if(e.getSource() == minimizeButton){
        minimizeButton.setBackground(Color.decode("#2ecc71"));
    }
}

@Override
public void mouseReleased(MouseEvent e) {
    if(e.getSource() == exitButton){
        System.exit(0);
    }

    if(e.getSource() == minimizeButton){
        super.setState(JFrame.ICONIFIED);
    }
}

@Override
public void mouseEntered(MouseEvent e) {
    if(e.getSource() == exitButton){
        exitButton.setBackground(Color.decode("#e74c3c"));
    }

    if(e.getSource() == minimizeButton){
        minimizeButton.setBackground(Color.decode("#16a085"));
    }
}

@Override
public void mouseExited(MouseEvent e) {
    if(e.getSource() == exitButton){
        exitButton.setBackground(Color.decode("#d35400"));
    }

    if(e.getSource() == minimizeButton){
        minimizeButton.setBackground(Color.decode("#1abc9c"));
    }
}
}

Here is the code for the custom buttons(I used JPanels). 这是自定义按钮的代码(我使用了JPanels)。 package com.SMS.GUI; 包com.SMS.GUI;

import java.awt.Color;
import javax.swing.JPanel;


final class GUIButton extends JPanel{
        GUIButton(int x, int y, int width, int height, String hexidecimal_colour){
        setBackground(Color.decode(hexidecimal_colour));
        setBounds(x, y, width, height);
    }

        GUIButton(int width, int height, String hexidecimal_colour){
        setBackground(Color.decode(hexidecimal_colour));
        setSize(width, height);
    }
}

This is how the frame looks before minimizing: 这是最小化之前的外观:

在此处输入图片说明

This is how it looks after: 它是这样的: 在此处输入图片说明

however when I use the minimize button and maximise again, the window is not in the correct format. 但是,当我使用最小化按钮并再次最大化时,窗口的格式不正确。

You really need to understand how Swing works if you want to customize a component. 如果要自定义组件,您确实需要了解Swing的工作原理。 Swing was designed to be used with layout managers . Swing旨在与layout managers一起使用。 The default layout manager for the content pane of a JFrame is a BorderLayout . JFrame的内容窗格的默认布局管理器是BorderLayout The default layout manager for a JPanel is a FlowLayout . JPanel的默认布局管理器是FlowLayout

The setSize() and/or setBounds() methods only work until the frame is "revalidated". setSize()和/或setBounds()方法仅在“重新验证”框架之前有效。 When the frame is restored to is size the layout managers for each component are invoked and all the components are displayed at their preferred size. 当框架恢复到其大小时,将调用每个组件的布局管理器,并以其首选大小显示所有组件。

titleBar = new JPanel();

So, the buttons on the "titleBar" get resized to their preferred size since they default FlowLayout is used. 因此,“ titleBar”上的按钮将调整为其首选大小,因为它们使用了默认的FlowLayout And the FlowLayout will then position the buttons in the center of the panel. 然后, FlowLayout会将按钮定位在面板的中央。

To fix this problem you need to override the getPreferredSize() method of the GuiButton class. 要解决此问题,您需要重写GuiButton类的getPreferredSize()方法。 Also, get rid of all the location related code. 同样,摆脱所有与位置相关的代码。 It is up to the layout manager to set the location/size. 由布局管理器来设置位置/大小。

Since you want the buttons aligned to the right of the panel, you will need to change the layout manager to use a right aligned FlowLayout . 由于您希望按钮与面板的右侧对齐,因此需要更改布局管理器以使用right aligned FlowLayout Read the FlowLayout API for the proper constructor to use when creating the layout manager. 阅读FlowLayout API,以获取在创建布局管理器时要使用的适当构造函数。

add(titleBar);

This adds the "titleBar" to the CENTER of the BorderLayout , so when the frame is revalidated, this panel will now cover the entire frame based on the rules of the BorderLayout . 这会将“ titleBar”添加到BorderLayoutCENTER上,因此,当重新验证框架时,此面板现在将根据BorderLayout的规则覆盖整个框架。

To fix this you can use: 要解决此问题,您可以使用:

add(titleBar, BorderLayout.PAGE_START);

Now the titlebar will only appear at the top for the frame. 现在,标题栏将仅出现在框架的顶部。

So you need to read the Swing tutorial on Layout Managers to understand these changes. 因此,您需要阅读有关布局管理器的Swing教程以了解这些更改。 The tutorial has working examples of both the BorderLayout and the FlowLayout . 本教程包含BorderLayoutFlowLayout工作示例。

I also suggest you read the section on How to Make Frames for simple frame basics, including a better structure for you code. 我还建议您阅读有关如何制作框架的部分, 获取简单的框架基础知识,包括为您的代码提供更好的结构。 The example code shows the order of statement execution such that the setVisible() is the last statement. 示例代码显示了语句执行的顺序,以使setVisible()是最后一条语句。

You could try to repaint or revalidate when you are Deiconifying you window. 您在取消窗口图标化时可以尝试重新绘制或重新验证。 To do this, implements WindowListener and use this method : 为此,实现WindowListener并使用以下方法:

@Override
public void windowDeiconified(WindowEvent e) {
    //back to normal you could use this.setState(JFrame.NORMAL);
    //do stuff here.
}

don't forget the this.addWindowListener(this); 不要忘记this.addWindowListener(this);

Also you extends JFrame so you could call this.setState(JFrame.ICONIFIED); 您还扩展了JFrame,因此可以调用this.setState(JFrame.ICONIFIED); instead of super method. 而不是super方法。 It's not a complete solution but it's definitly a problem of component painting. 这不是一个完整的解决方案,但绝对是组件绘制的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM