I am trying to make a chess engine as a fun project, but for that I really want to make a GUI. The problem is that I have no experience with this, so I am a little stuck. I managed to create the board, but there are two things I have no idea how to do and looking online just confuses me further.
How do I add the pieces to the board, based on what the board looks like in the computers memory. (so for example if the engine makes a move, I want that move to also happen on the gui, how would I link the two?)
How do I figure out what square the user is clicking on in the gui?
This is the code I have so far for the gui, it's not much, but it's honest work
private final JFrame gameFrame;
private Board board;
public Table() {
this.board = new Board();
this.gameFrame = new JFrame("Chess");
this.gameFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.gameFrame.setSize(527, 550);
JPanel panel = new JPanel() {
#Override
public void paint(Graphics g) {
boolean white = true;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (white) {
g.setColor(new Color(240, 217, 181));
}
else {
g.setColor(new Color(181, 136, 99));
}
g.fillRect(j * 64, i * 64, 64, 64);
white = !white;
}
white = !white;
}
}
};
this.gameFrame.add(panel);
this.gameFrame.setVisible(true);
}
I know I am probably asking questions with complicated answers, but I am just looking for something I can look up or some general directions
One way and perhaps the the most useful is to implement a mouseListenerand then get the x y position from one of the methods.
Write a class to extend MouseAdapter.
override the desired empty methods.
then add an instance of that class to the frame via addMouseListener (and perhaps addMouseMotionListener).
Then when you do some action with the mouse, you can get the coordinnates from the MouseEvent. It helps to put some print statements in each method to observe what is going on (what method is processing what mouse movement).
The above will serve to demonstrate the process. But later on you should actually add the listener on a JPanel and add the JPanel to the frame.
Related
I want to build a 2d array of toggle buttons in Java that when I click on a button, it passes from green to red, how can I do this? The following code creates the array of buttons.
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Container implements ActionListener {
private static JFrame container;
private static JToggleButton[][] butoes;
public static void main(String args[]) {
container = new JFrame("Game of Life");
butoes = new JToggleButton[20][20];
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
butoes[i][j] = new JToggleButton();
}
}
container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container.setLayout(new GridLayout(20, 20));
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
container.add(butoes[i][j]);
}
}
container.pack();
container.setSize(700, 700);
container.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent evento) {
}
}
UIManager.put("ToggleButton.select", yourColorHere);
From
https://community.oracle.com/thread/1485709?start=0&tstart=0
ControlAltDel's answer is correct, and should likely be used as the solution for this specific question in this context. However, being general, there are a couple things here. First, when it comes to reacting to GUI changes in Swing, you're going to want to familiarize yourself with the listener paradigm it uses. This paradigm allows you to react to (almost) any GUI event you want, and modify your program appropriately.
However, in this case, that's tangential knowledge (I'm leaving it in the answer because it's still very important to know when dealing with Swing UIs though). The problem is that the selected color is only exposed through the UI of the button, so, in order to update it, you would need to change the default UI associated with this specific button (there are alternative approaches, but this is one of the easier ones).
This does seem more cumbersome than just updating the UIManager, as ControlAltDel proposed. But it's also important to note that changes to core properties in the UIManager are global (as MadProgrammer eluded to). If you update the selected toggle button color in the UIManager, you're updating it for every instance of JToggleButton, which, while in this specific scenario might not be a bad thing, is definitely something to keep in mind in practice.
Taking all of this into consideration, one potential fix would be to replace this:
butoes[i][j] = new JToggleButton();
With something like this:
JToggleButton b = new JToggleButton();
b.setBackground(Color.GREEN);
b.setUI(new MetalToggleButtonUI() {
#Override
protected Color getSelectColor() {
return Color.RED;
}
});
butoes[i][j] = b;
Recommend checking out this lesson on the Oracle site, the javadoc for JToggleButton, and this other SO question.
I am developing a simple game where have to write words. So I taught to make a TextArea where the words typed goes, to this I need a scroll to can see all words. But i have a render method that have this:
public void onRender(Graphics2D g) {
g.drawImage(imgBG, 0,0, null); //draws my background
g.setColor(Color.WHITE);
g.setFont(titulo);
g.drawString("Type the Word!", 260, 240);
g.setColor(Color.darkGray);
for(int i=0;i < wordFind.length();i++)
{
g.fillRect(inicioTraco+(60*i),yTraco,40,10);
}
if(tag_s == true)
{
tag_s = false;
g.setFont(titulo);
g.drawString("s",posicao, 100);
}
this.getMainWindow().add(new JTextArea("Test",10,20));
}
getMainWindow is a method that return my main JFrame, and i put this JTextArea to show the words.
But it is not appearing in my game.
I taught to make a white rect (fillrect) but it will not have scoll.
So I don't know what to do. Can someone clear my mind?
thanks.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm having a couple of different problems with my code, most of them are GUI based problems but i do have one actionevent problem. I will post my code in sections first then I will point out what the issue is specifically with each section. *note all of my code will be in order of how is actually in my IDE.
If you wish to copy my code without all of the other stuff here it is on pastebin: http://pastebin.com/HHjRRtGZ
My imports:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*; //Makes it a Japplet
import java.util.Random;
My Program Starts here:
public class Hangman extends JApplet implements ActionListener {
// How many times you can guess the wrong letter till you lose
static final int DEAD = 7;
private int errors; // amount of errors
private String message; // Message displaying either Error or Victory
private String information; // Secondary Message
private String RealWord; // The Real word
private StringBuffer GuessWord;// The Guessed word
private Button StartBtn; // The Restart Button
private Button GoBtn; // The Go Button
private TextField LetterBox; // The LetterBox
My ActionEvent:
public void actionPerformed(ActionEvent e){
if (e.getSource() == StartBtn){
initGame();
}
if (e.getSource() == GoBtn){
processTurn();
LetterBox.setText("");
repaint();
}
}
Problem One:
The problem that I am having with my Action event is that when I hit the StartBtn it does not reinitialize everything. Nothing is cleared. Nothing is done. It doesn't do anything. So that's the issue there.
My init() function (This is where one of my problems lie.
public void init() {
// Create a "Textbox" for the letter guessing
LetterBox = new TextField();
//Create my buttons and labels
StartBtn = new Button("Restart");
GoBtn = new Button("Go");
//Add the elements to the applet
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
p.add(StartBtn);
p.add(new Label("Guess a letter"));
p.add(LetterBox);
p.add(GoBtn);
add(p, BorderLayout.SOUTH);
//Make buttons event listeners
StartBtn.addActionListener(this);
GoBtn.addActionListener(this);
//Startup the Game
initGame();
}
Problem 2 (MAIN PROBLEM):
The problems I have with my Init code that affect my GUI is that the actual word guess area and the hangman area are kind of messed up. It's hard to explain, so i'll show you an image. The Backdrop for almost all of the form is completely transparent. So it just uses a still image of whatever it was on top of as it's back ground.
Problem 3:
There are some other issues with the image as you can see. The code is further down for those parts however. But as you can tell, the messages do not clear and just write over each other, even though I specify them to (which you will see further down).
Problem 4:
Now before you guess any letters, the word is hidden with a "" but when you guess a correct letter for the word it's supposed to replace the "" with the correct letter guessed. However it just put's it on top of it (you will see the code for this below as well).
This is the Game initializer
public void initGame() {
//Set the errors to 0
errors = 0;
//Enter the wordslist, separated by a | here
String str = "write|program|receive|positive|variables|temporary|good|bad|test";
String[] temp;
//delimiter
String delimiter = "\\|";
// given string will be split by the argument delimiter provided.
temp = str.split(delimiter);
//Create the Random Seed Generator
Random RandGenerator = new Random();
//Generate my Random Number
int randomInt = RandGenerator.nextInt(temp.length);
RealWord = new String(temp[randomInt]);
char positions[] = new char[RealWord.length()];
Right here is where it replaces the unguessed characters on screen with a "*".
for (int i = 0; i < RealWord.length(); i++) {
positions[i] = '*';
}
String s = new String(positions);
GuessWord = new StringBuffer(s);
LetterBox.setText("");
//Delete Messages
message = "";
information = "";
repaint();
}
My Painting function
#Override
public void paint(Graphics g) {
int BaseY = 250;
//THE HANGING STAND
if (errors > 0) { //1 Error
g.drawLine(90, BaseY, 200, BaseY); //The ground
g.drawLine(125, BaseY, 125, BaseY-100); //The bar going up
g.drawLine(125, BaseY-100, 175, BaseY-100); //The sidebar
g.drawLine(175, BaseY-100, 175, BaseY-75); //The Rope
}
//THE PERSON
if (errors > 1) {
g.drawOval(170, BaseY-75, 10, 12); // The Head
}
if (errors > 2) {
g.drawLine(175, BaseY-62, 175, BaseY-45); // The Body
}
if (errors > 3) {
g.drawLine(165, BaseY-65, 175, BaseY-55); // Left Arm
}
if (errors > 4) {
g.drawLine(185, BaseY-65, 175, BaseY-55); // Right Arm
}
if (errors > 5) {
g.drawLine(170, BaseY-30, 175, BaseY-45); //Left Leg
}
if (errors > 6) { //7 Errors
g.drawLine(175, BaseY-45, 180, BaseY-30); // Right Left
}
//Show Messages/Errors
g.drawString(message, 40, BaseY+25);
g.drawString(information, 25, BaseY+45);
g.drawString(new String (GuessWord), 140, BaseY-120);
g.drawString(new String("WELCOME TO HANGMAN!"), 75, 40);
}
This is where alot of the magic happens. This is the processTurn Function
private void processTurn() {
String s, t;
char a;
s = LetterBox.getText();
a = s.charAt(0);
if (!Character.isLetter(a)) {
message = "Only enter letters please.";
return;
}
if (s.length() > 1) {
message = "One letter at a time please.";
return;
}
//Check if letter has been used already
t = new String(GuessWord);
if (t.indexOf(s) != -1) {
message = "You have already guessed with that letter!";
return;
}
//If the letter you guessed does not occur in the Real Word
if (RealWord.indexOf(s) == -1) {
message = "";
errors++;
if (errors==DEAD) {
message = "Sorry, you lose";
information = "Click restart to try again!";
//INSERT MOVING HANGMAN HERE.
}
return;
}
This is where the "*" is supposed to be replaced with the correctl guessed letter but it doesn't work correctly!
//Replace stars in the Guessed Word with the found letter
for (int i = 0; i < RealWord.length(); i++) {
if (RealWord.charAt(i) == a) {
GuessWord.setCharAt(i, a);
}
}
t = new String(GuessWord);
//If all of the stars have been filled, then you win!
if (t.indexOf('*') == -1) {
message = "You have won!";
return;
}
//Delete the Message
message = "";
repaint();
}
Main Function
public static void main(String[] args) {
JFrame frame = new JFrame();
JApplet applet = new Hangman();
applet.init();
applet.start();
frame.add(applet);
frame.setSize(300, 400);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Any and all assistance will be greatly appreciated :) Thanks in advance!
This is caused by the basic fact that you have broken the paint chain.
Painting in AWT/Swing is made of a chain of method calls. If you neglect to maintain this chain, you start ending up with paint artifacts, in the form you are seeing.
The Graphics context is a shared resource, that is, every component painted during any given paint cycle will be given the same Graphics resource. Each component is expected to prepare the Graphics context before painting to it...
To fix the problem, in all your paint methods, you should be calling super.paint(g) to ensure that the paint chain is maintained and that the Graphics context is preapred for the individual components painting needs.
Having said that. It is not recommended to override paint of top level containers. Instead, it is recommended that you perform your custom painting using something like a JPanel and override it's paintComponent method instead (ensuring that you call super.paintComponent as well!)
This has a least two basic benefits. The first is, you can know decide where the panel should be displayed, for example, you could add it to an JApplet or JFrame or other container as you see fit. It is double buffered by default. This means you won't see any flicker when the painting is updated.
You should consider breaking your application down into small panels, focusing on each of the components needs separately. This will help reduce the complexity of your application and make it easier to manage the individual needs of each section of your application.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
The problem is that you're painting directly on JApplet. You should not paint directly on top level container such as JFrame or JApplet. Instead, use JComponent or JPanel. Override paintComponent() for painting rather than paint() and don't forget to call super.paintComponent(g).
Take a look at Performing Custom Painting tutorial for more information.
Consider refactoring your code by moving all the current logic and painting into a new JPanel which will be used as applet content. Then, add this panel to the applet.
EDIT:
The source of the problem is not calling super.paint() in you painting implementation. Overriding paint() is not necessary and usually not recommended in many Swing applications. JComponent.paint() (a superclass for all Swing components) handles painting the content, borders, and children of a Swing component. And by neglecting a call to super.paint() you are disrupting the painting of all these details.
Take a looks at A Closer Look at the Paint Mechanism for more details about painting cycle.
I made some menu and it is to update conmmon variables (for text on grid) then the out-of-focus dialog must repaint the grid. Here is the screenshot:
The main control panel is always at top position and 'Data Display' panel is always sitting behind it. When press a button on front panel, Data Display must update its grid. Currently, the common variable 0.4 on the grid is updated by adding listener and works fine. But the grid itself is not repainting anymore. How can I repaint the out-of-focus dialog in real time?
Here is the code of the front panel:
public class MainDisplayForm extends javax.swing.JFrame {
Storage st = new Storage();
DisplayForm dF = new DisplayForm();
....
public MainDisplayForm() {
initComponents();
Btn_IncreaseGain.addActionListener(new ButtonListener_IncreaseGain());
}
....
} //MainDisplayForm ends here.
class ButtonListener_IncreaseGain implements ActionListener {
DisplayForm dF = new DisplayForm();
Storage st = new Storage();
ButtonListener_IncreaseGain()
{
}
public void actionPerformed(ActionEvent e) {
st.iGain = 20;
dF.revalidate();
dF.repaint();
System.out.println("Testing");
}
}//Listener ends here.
Here is code of Data Display:
public void paint(Graphics g)
{
g2 = (Graphics2D) g;
paintComponents(g2);
//added numbers are for adjustment.
int x = this.jPanel1.getX()+8;
int y = this.jPanel1.getY()+30;
int width = this.jPanel1.getWidth()+19;
int height = this.jPanel1.getHeight()+40;
//labelling voltages
label0.setText(st.zero);
label1.setText(st.v1);
label2.setText(st.v2);
label3.setText(st.v3);
label4.setText(st.v4);
label5.setText(st.v3);
label6.setText(st.v4);
g2.setColor(Color.darkGray);
for(int i=x; i<width; i=i+80)
{
g2.drawLine(i, y, i, height);
}
int j = 0;
for(int i=y; i<height; i=i+80)
{
j++;
//st.iGain
g2.setColor(Color.orange);
if(j==1)
{
double k1 = st.iGain * 0.4;
st.v1 = Double.toString(k1);
g2.drawString(st.v1, x+5, y+10);
}
if(j==2)
{
double k2 = st.iGain * 0.3;
st.v2 = Double.toString(k2);
g2.drawString(st.v2, x+5, y+90);
}
g2.setColor(Color.DARK_GRAY);
g2.drawLine(x, i, width, i);
....
} //grid info is not completed yet.
Thanks,
Focus isn't the issue and has nothing to do with your current problem. The solution is to change the properties of the data grid by updating fields it contains via setter methods and calling repaint on the JComponent (perhaps a JPanel, or some other component that derives ultimately from JComponent) held by the data grid. The paintComponent method of this component should use its class fields to update what it draws.
You almost never paint in the paint method of a JComponent and certainly you don't want to draw directly into a top-level window. You also probably don't want to set text of JLabels, JTextFields, or any other JTextComponent. from within paint/paintComponent.
I can't see why your code is not working and can only guess that the likely cause of your problem is in code not shown.
Edit 1:
Just guessing, but you may have a problem of references. I notice that your listener class creates new DisplayForm and Storage objects:
DisplayForm dF = new DisplayForm();
Storage st = new Storage();
There's a good possibility that these objects are not the ones being displayed, especially if you create these objects elsewhere and display them. Again I'm just guessing since I don't see the rest of your code, but perhaps you should to pass references for these objects into the DisplayForm via constructor or setter method parameters.
Edit 2:
e.g.,
public void setDisplayForm(DisplayForm dF) {
this.dF = dF;
}
// same for Storage
And in the main program:
public MainDisplayForm() {
initComponents();
ButtonListener_IncreaseGain btnListenerIncreaseGain = new ButtonListener_IncreaseGain();
btnListenerIncreaseGain.setDisplayForm(....);
btnListenerIncreaseGain.setStorage(....);
Btn_IncreaseGain.addActionListener(btnListenerIncreaseGain);
}
I'm attempting to create my own custom ToolTip for a program I've ported to Java, I'm trying to match the original programs ToolTips (it was written in Delphi). I've got some code that allows me to draw "inside" a ToolTip but for some reason, if I Override paint(Graphics g, JComponent c) and leave it blank it still draws a ToolTip, and anything I attempt to draw will be drawn "inside" this little boxed ToolTip and I can't draw "outside" of it.
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicToolTipUI;
class MultiLineToolTipUI extends BasicToolTipUI {
#Override
public void paint(Graphics g, JComponent c) {
//int mY = 0;
//int mX = 0;
//int xPoints[] = {mX, mX, mX + 15};
//int yPoints[] = {mY, mY + 25, mY + 25};
//Polygon p = new Polygon(xPoints, yPoints, 3);
//g.setColor(Color.BLACK);
//g.fillPolygon(p);
//g.fillRoundRect(mX, mY, 100, 50, 30, 30);
}
public static void main (String args[])
{
JButton button = new JButton ("Mouse Over ME!") {
public JToolTip createToolTip() {
MultiLineToolTip tip = new MultiLineToolTip();
tip.setComponent(this);
return tip;
}
};
//JButton button = new JButton("Mouse Over ME!");
button.setToolTipText("Hello, World");
JFrame frame = new JFrame("Basic SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( button );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
static class MultiLineToolTip extends JToolTip
{
public MultiLineToolTip()
{
setUI(new MultiLineToolTipUI());
}
}
}
This is what I have, and like I said, even without the lines in paint it's drawing on it's own.
Any advice to get around this? Or a better way to go about what I'm trying to do?
CLARIFICATION: The first answer by Camickr was very helpful, however I should clarify my goal is to get the box that is automatically drawn from somewhere outside of paint to go away, or be invisible.
The size of the tool tip is determined by the text. Add:
System.out.println( c.getSize() );
to the paint(...) method to see the size of the tool tip. You are trying to paint outside its bounds. If you want to override the default size then you need to set the preferred size yourself. I think you want:
public Dimension getPreferredSize(JComponent c)
{
return new Dimension(100, 50);
}
Edit: A tooltip is a component with a border and a background. If you want to remove them you can use:
tip.setOpaque(false);
tip.setBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0));
This will only work when to tooltip is fully contained withing the frame. When the tooltip is displayed outside the bounds of the frame, then the tooltip is added to a JWindow, in which case you will see the background of the window. I don't know how to disable this behaviour because all Swing components must be painted within the bounds of a top level container.