How to create customize title bar with close button on jFrame? - swing

I want to create a customised title bar for my JFrame. I can remove the default title bar with
JFrame.setUndecorated(true)
Now i need to create a customised title bar for my JFrame with a close button?

Without having done that ever, I think I would go this way:
Indeed set the JFrame to undecorated
Extend JRootPane to add an additional field titleBar
Create a TitleBar component holding the title, the close button, etc...
Set a new LayoutManager on that JRootPane (have a look at JRootPane.RootLayout) and layout the components in the appropriate order (first the title bar, then below the menubar, then below the content pane)
Set an instance of that extends RootPane on your JFrame
There are maybe better ways.

I'm not quite sure of how you want to customize the close button, but maybe this can point you in the right direction: How can I customize the title bar on JFrame?
EDIT: Here's an updated working link to a forum about customizing his GUI and one user posted code on his creation of a simple GUI: Here
It looks like you can just modify his removeComponents method and create an addComponents method to fit your needs.

The Code According to the Above Link :
(Edited for Java 8)
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
class Testing {
public void buildGUI() throws UnsupportedLookAndFeelException {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame f = new JFrame();
f.setResizable(false);
removeMinMaxClose(f);
JPanel p = new JPanel(new GridBagLayout());
JButton btn = new JButton("Exit");
p.add(btn, new GridBagConstraints());
f.getContentPane().add(p);
f.setSize(400, 300);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
btn.addActionListener((ActionEvent ae) -> {
System.exit(0);
});
}
public void removeMinMaxClose(Component comp) {
if (comp instanceof AbstractButton) {
comp.getParent().remove(comp);
}
if (comp instanceof Container) {
Component[] comps = ((Container) comp).getComponents();
for (int x = 0, y = comps.length; x < y; x++) {
removeMinMaxClose(comps[x]);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new Testing().buildGUI();
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(Testing.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
}
may Work Fine but what if user also Want to set a L&F
such as nimbus

There are really three ways to approach this:
Set the frame to undecorated and implement everything, which includes control buttons, snapping, resizing and moving.
Get the root pane of the JFrame and directly edit that pane. You will need to add the control buttons and the snapping behaviour.
Use JNI to get the window's handle at the creation of a JFrame to get the control of it's attributes. This is better explained in this post. I have also built a little project which is basically an extension of the JFrame class that handles everything that needs to be dealt with... This last approach does not break native functions like snapping and resizing. But you do need to create the control buttons again since you have a new title bar if you want to build it from scratch.

Related

Minimize a resizable JDialog

I'm working on an swing application with a main window (which extends JFrame) from which several child windows can be opened (more than 1 contemporarily).
These windows are all non-modal and resizable.
So far, I implemented these 'child' windows as a JFrame. However, I get a new icon on my Windows taskbar for each opened Window.
I therefore tried to implement these windows as a JDialog with type ModalityType.MODELESS.
Looks OK except that a JDialog has no minimize button.
Is there a way to resolve this?
I.e., I need to create non-modal and resizable child windows that can be minimized.
JInternalFrame is not an option since the main frame is not just a container with a JDesktopPane and child windows should be able to cross the borders of the main window.
For those interested:
Child windows register and unregister themselves on the main window when being opened/closed.
The main window has a menu with a 'Windows' item and child windows are added/removed from that menu upon registration/unregistration.
The user can switch between the various windows by selecting an item within this menu.
I am offering two suggestions.
A. Don't use the close button to get rid of the contents.
B. Set the type of child jframes to be utility.
I think having the JDialog close button destroy data is setting your users up for data loss. I would instead use the close to just hide the window, and then have controls inside of the dialog to cancel/finish/restart.
import java.awt.*;
public class DiFrame{
static JDialog log;
static JFrame ame;
public static void main(String[] args){
JFrame frame = new JFrame("Father of two");
JButton one = new JButton("dialog");
one.addActionListener( evt->{
if(log==null){
log = new JDialog(frame, "dialog child", false);
log.add(new JTextArea("fresh start"));
log.pack();
log.setVisible(true);
} else{
log.setVisible(true);
}
});
JButton two = new JButton("frame");
two.addActionListener( evt->{
if(ame==null){
ame = new JFrame("frame child");
ame.add( new JTextArea("fresh start") );
ame.setType(Window.Type.UTILITY);
ame.pack();
ame.setVisible(true);
} else{
ame.setVisible(true);
}
});
frame.add(one, BorderLayout.NORTH);
frame.add(two, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Click the dialog button and it shows the dialog. Then the text area can be modified. When the dialog is closed it can be re-opened.
Click the frame button and a jframe is shown. ( I actually cannot check if this shows up as a new application because it doesn't on my computer anyways. )

How to change the way a copy-paste text behaves?

I'm creating a website and I wish to present some lines of code in there,but I can't find a stylish way to do it. For example let's take a simple HelloProgram written in JAVA. I want to make it appear like so
import acm.graphics.*;
import acm.program.*;
public class HelloProgram extends GraphicsProgram {
public void run() {
add (new GLabel("I love Java." ,100,75));
add( new GLabel(" Marios Theofilos" ,600,450));
// The x and y coοrdinates may vary depending on your computer
}
}
and not like that
import acm.graphics.*;
import acm.program.*;
public class HelloProgram extends GraphicsProgram {public void run() {
add (new GLabel("I love Java." ,100,75));
add( new GLabel(" Marios Theofilos" ,600,450));
}
}
.Basically, just using copy paste does not work. I have tried text-aligning in both CSS and HTML. The best possible solution seems to be to make a div box and then put the code there. I've tried creating the box,but I wasn't able to change the way the text behaved when I copy and paste. Also, I can't create the desired effect by hand,or I haven't found out how yet.
That is exactly what the <pre> tag is there for: to render preformatted text:
<pre>
import acm.graphics.*;
import acm.program.*;
public class HelloProgram extends GraphicsProgram {
public void run() {
add (new GLabel("I love Java." ,100,75));
add( new GLabel(" Marios Theofilos" ,600,450));
// The x and y coοrdinates may vary depending on your computer
}
}
</pre>
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre
Take care to htmlescape() the content when you create the node programmatically!

Force JScrollPane and JPanel to repaint

I have a JScrollPane that holds a JPanel. The layout on the JPanel is a GridBagLayout. On that JPanel, I add a number of custom components - each is a JPanel with 3 JLabels.
The first time in the program I lay all of this out, it works fine. When I invoke the code to add another custom component to the JPanel, the panel appears empty, but I can determine by examining the contents of the JPanel that my components are actually there. If I resize the JDialog in which this all sites, the JPanel will paint properly. It also works if I scroll the JScrollPane horizontally even a tiny bit.
I use the same method for the initial layout as I do when adding an item.
I've tried various combinations of repaint(), invalidate() and doLayout() but nothing seems to work all the time. I've run into this situation before and have never been able to fully solve it. Any suggestions?
Running under OpenJDK 7u25. Below is the code that lays out the scroll pane and panel.
private void displayRelatedBug(ArrayList<Bug> a_bugs) {
// sort the bugs by ID
ArrayList<Bug> l_sorted = new ArrayList<>(a_bugs);
Collections.sort(l_sorted);
pnlRelatedBugs.removeAll();
pnlRelatedBugs.setLayout(new GridBagLayout());
GridBagConstraints l_gbc = new GridBagConstraints();
l_gbc.gridx = 0;
l_gbc.gridy = 0;
l_gbc.gridwidth = 1;
l_gbc.gridheight = 1;
l_gbc.anchor = GridBagConstraints.NORTHWEST;
l_gbc.fill = GridBagConstraints.NONE;
l_gbc.insets = new Insets(3, 4, 0, 0);
for (Bug r : l_sorted) {
pnlRelatedBugs.add(new RelatedBugDisplay(r, this), l_gbc);
l_gbc.gridy++;
}
// add a filler at the bottom to push it up
l_gbc.weighty = 1.0;
pnlRelatedBugs.add(new MMPanel(), l_gbc);
// add a filler on the right to push them left
l_gbc.weighty = 0.0;
l_gbc.weightx = 1.0;
l_gbc.gridx++;
pnlRelatedBugs.add(new MMPanel(), l_gbc);
// try in vain to make it show up!!!
pnlRelatedBugs.invalidate();
pnlRelatedBugs.doLayout();
pnlRelatedBugs.repaint();
scrollerRelatedBugs.doLayout();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
pnlRelatedBugs.repaint();
scrollerRelatedBugs.repaint();
// this seems to help if the scroll bar is showing
scrollerRelatedBugs.getHorizontalScrollBar().setValue(1);
scrollerRelatedBugs.getHorizontalScrollBar().setValue(0);
}
});
}
Whenever you add/remove components from a visible panel, the basic code is:
panel.remove(...);
panel.add(...);
panel.revalidate();
panel.repaint();
Without a proper SSCCE we can't really tell what your code is doing.
If you do add/remove/replace/others actions with components on showing container, you must to revalidate and repaint your container, to which you add components for proper displaying.

Graphics plain 2D objects are not rendered while an action occurred

I am designing a game in Swing. Currently I am designing the maze for this game. The maze is generated by using Depth First Search algorithm. In my main JFrame, I have some JPanel. One JPanel, named mazePanel contains the maze. There are some other JPanel also, which contains the JButton for controlling. Following is the mazePanel code.
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class MazePanel extends JPanel {
private MazeGenerator mazeGenerator;
private boolean startNewMaze = false;
public MazePanel() {
setBorder(BorderFactory.createTitledBorder("Maze"));
setToolTipText("This is the maze");
}
public void addNewMaze() {
startNewMaze = true;
mazeGenerator = new MazeGenerator();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (startNewMaze) {
mazeGenerator.generate(g);
startNewMaze = false;
}
}
}
There is one JButton, which calls the method mazePanel.addNewMaze() and set the Boolean startNewMaze to true. After setting the startNewMaze, maze should be generated. i.e. mazeGenerator.generate(g) is inside if() condition. Method mazeGenerator.generate(g) recursively draw the random maze. That is why I don’t want to run this method not more than once.
Up to this everything is looking fine. But while I am running the main JFrame and clicks on the JButton, maze is not rendered in the mazePanel. Sometimes when I minimize and maximize the JFrame, maze rendered (might be because of repaint() occur). Even if I comment mazeGenerator.generate(g) inside if() condition and put some g.drawString(). The string is not rendered while action performed (i.e.Pressing JButton).
Where is the problem? Please help.
Thank you.
So basically you have a JPanel which contains nothing, you call a method unknown to Swing and expects the paintComponent method is magically called when you change the state of a private field.
You already discovered that minimizing and maximizing again solves your problem due to a repaint. That should be sufficient information to know you have to trigger a repaint yourself when you press that button.
If you would have followed the suggestion from #kleopatra to, and I quote,
change the state and then trigger the revalidation/painting
you would already have solved your problem

Better choice: TextLayout or JTextComponent for an "ellipse with editable text" component?

If you've ever used Visio or a UML class diagram editor, you have an idea of what I'm trying to accomplish: Within a JFrame, users can add ellipses that enclose a small editable text field. These ellipses can be repositioned within the frame when the user drags them. Clicking on an ellipse causes the text to become editable: a carat appears, highlighting a substring is possible, etc.
I've got the basic structure set up: the 'ellipse' is a self-contained component, with methods called on it from the containing JFrame and its listeners. I've tried two approaches:
in the component's draw() method, use a TextLayout to find bounds, position the contained text within the ellipse, and draw it to the frame using TextLayout's draw(). This is fast. Dragging the components around in the JFrame, mouse-over and mouse-click behavior are all straightforward. However for the editing functionality it looks like I will need to write a lot of custom code to handle hit testing, carat positioning, text highlighting, line wrapping, etc.
having the component contain a reference to the containing JFrame, and adding or repositioning a TextComponent in that JFrame after drawing the ellipse. This has the advantage of all the built-in TextComponent behavior for editing and line wrapping. But the logistics are really sloppy, and positioning the TextComponent becomes messy too - especially when the user drags the component around.
I'm quite possibly thinking about this all wrong. Can anyone suggest a simple way to do this that I haven't yet stumbled across?
Why don't you combine both your approaches. As long as you are editing, display the text component, otherwise paint all text using a TextLayout. The following example code shows such an approach extending a simple JComponent. It draws a rectangular shape with some text in it and if you click inside it shows an editing possibility. As soon as you click outside again, the component vanished. Note that all the edit-handling functionality is missing in this basic example.
class TestComponent extends JComponent {
JTextArea jta = new JTextArea("12345");
public TestComponent() {
setPreferredSize(new Dimension(400, 400));
setLayout(null);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (e.getX() >= 40 && e.getX() <= 200 && e.getY() >= 40 && e.getY() <= 80) {
TestComponent.this.add(jta);
jta.setBounds(42, 42, 156, 36);
} else {
TestComponent.this.remove(jta);
}
repaint();
}
});
}
});
}
#Override
public void paintComponent(Graphics _g) {
Graphics2D g = (Graphics2D) _g;
g.drawRect(40, 40, 160, 40);
TextLayout layout = new TextLayout("12345", g.getFont(), g.getFontRenderContext());
layout.draw(g, 42, 42 + layout.getAscent());
}
}