Brief description of Program
Hi guys. I got bored this morning and decided to write a graphing program. Eventually i'll be able to run things like Dijksta's Algorithm on this software.
When anything changes on screen, a call to the repaint method of the JPanel where everything is painted to is made. This is the JPanel paint method:
public void paint(Graphics g)
{
for(Node node : graph.getNodes()){
node.paint(g);
}
for(Link link : graph.getLinks()){
link.paint(g);
}
}
It simply cycles through each element in the lists, and paints them.
The paint method for the node class is:
public void paint(Graphics g)
{
g.setColor(color);
g.drawOval(location.x, location.y, 50, 50);
g.setColor(Color.BLACK);
g.drawString(name, location.x + 20, location.y + 20);
}
And for the link it is:
public void paint(Graphics g)
{
Point p1 = node1.getLocation();
Point p2 = node2.getLocation();
// Grab the two nodes from the link.
g.drawLine(p1.x + 20, p1.y + 20, p2.x + 20, p2.y + 20);
// Draw the line between them.
int midPointX = ((p1.x + p2.x) / 2) + (100 / (p2.x - p1.x));
int midPointY = ((p1.y + p2.y) / 2) + 30;
// Compute the mid point of the line and get it closer to the line.
g.setColor(Color.BLACK);
g.drawString(String.valueOf(weight), midPointX, midPointY);
}
The Problem
The issue I am having arises when I use the JOptionPane class. When I select the option to add a new node, and select where to place it, an inputDialog pops up, asking for the node's name.
The nodes are added fine, for this behaviour occurs:
Is this a common problem; an issue with paint or repaint perhaps?
Nonetheless, here is the code that calls the inputDialog:
Function addNode = functionFac.getInstance(state);
String name = "";
while(!name.matches("[A-Za-z]+")) {
name = JOptionPane.showInputDialog("Please enter the name of the node.", null);
}
addNode.execute(stage, new NodeMessage(arg0.getPoint(), name));
PS: Function is an interface type that I have written.
"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods.
"If you do not honor the opaque property you will likely see visual artifacts."—JComponent
See also this Q&A that examines a related issue.
Related
i tried making a program that will create a visual every time you click, but it didnt work so i stripped down the code to a sample of what didnt work.
at first i thought that the problem was that i didnt have a draw function so processing didnt search for events but when i added the println it still didnt trigger...
can you help me find where i was wrong??
void setup(){
size(500, 400);
}
void draw(){;} // listens to events
void mouseClicked(){
println("d");
}
edit1: goldenCucumber told me to get rid of two curly braces, i forgot to delete them (i dont think this is the problem)
edit2:
people asked for the full code:
void setup(){
size(500, 400);
colorMode(HSB, 100);
draw_gradients();
}
void draw_gradients(){
color c1 = color(random(100), 100, 100);
color c2 = color(random(100), 100, 30);
for(int y = 0; y < height;y++){
float n = map(y, 0, height, 0, 1);
color newc = lerpColor(c1, c2, n);
stroke(newc);
line(0, y, width, y);
n += 0.01;
}
}
void draw(){;} // listens to events
void mouseClicked(){
println("d");
draw_gradients();
}
If you remove two unnecessary "}" signs after "size(500, 400);" it works correctly, just tested. I am not sure though if you are aware that println() function only prints text to Processing console in the bottom of the code window. It does not draw it in animation window.
I'm doing a project for school in witch I have to simulate an ant colony and also show it in a graphics user interface.
The whole project is almost complete but I neet to implement a zoom feature for my jPanel.
I've found a thread on this site with basically what I need.Here's the link:
Zooming in and zooming out within a panel
What Thanasis made in that thread is what I basically need but I have no Idea how to implement it inside my code with the other classes.
I am a newbie in Graphic User Interface and we are basically learning and understanding it by doing this project so forgive me if the answer is Super easy and I'm asking for the answer.
I can provide code for the Pannel and Window classes.
I've allready tried launching it without anything thinking that it will work directly on my jpanel but it didn't of course.also tried to call it in my main but that didn't work either. Here's my paintComponent from my panel . I basically do this for everything that shows(ants, colony, food).
public void paintComponent(Graphics g){
int tailletab = this.gri.getTab().length;
//On récupère le tableau de la Grille
int[][] gril = this.gri.getTab();
int taillecarre;
int xcol = this.colo.getPos().getX();
int ycol = this.colo.getPos().getY();
int xsou = this.source.getPos().getX();
int ysou = this.source.getPos().getY();
if(tailletab<=50){
taillecarre = tailletab/4+2;
}else{
if(tailletab<60){
taillecarre = tailletab/5+1;
}else{
if(tailletab<70){
taillecarre = tailletab/7+1;
}else{
if(tailletab<80){
taillecarre = tailletab/8;
}else{
if(tailletab<90){
taillecarre = tailletab/10;
}else{
taillecarre = tailletab/13;
}
}
}
}
}
for(int i=0; i<tailletab; i++){
for(int j=0; j<tailletab; j++){
if(gril[j][i]==0){
if(j==xcol && i==ycol){
g.setColor(new Color(102, 51, 0));
g.fillRect(xcol*taillecarre, ycol*taillecarre,taillecarre,taillecarre);
g.setColor(Color.BLACK);
g.drawRect(xcol*taillecarre, ycol*taillecarre,taillecarre,taillecarre);
}else{
if(j==xsou && i==ysou){
g.setColor(Color.RED);
g.fillRect(xsou*taillecarre, ysou*taillecarre,taillecarre,taillecarre);
g.setColor(Color.BLACK);
g.drawRect(xsou*taillecarre, ysou*taillecarre,taillecarre,taillecarre);
}else{
g.setColor(Color.BLACK);
g.drawRect(j*taillecarre, i*taillecarre, taillecarre, taillecarre);
}
}
}else{
g.setColor(Color.BLACK);
g.drawRect(j*taillecarre, i*taillecarre, taillecarre, taillecarre);
g.fillRect(j*taillecarre, i*taillecarre, taillecarre, taillecarre);
}
}
}
}
The answer of Andreas Holstenson in the link you provided is better than Thanasis' because you shouldn't override paint but paintComponent as you correctly did, and Thanasis doesn't overwrite the transformation but tries to be dumb-clever about not progressively updating the transform. If you lost me, just forget that answer altogether.
Otherwise, the choice of whether to use AffineTransform or not does not matter as the result is the same. Arguably, AffineTransform is easier to use.
To answer your question, put the additional scale/translate code at the top of that method and all graphics drawn after that should be zoomed (even if if you use g instead of g2).
#Override
protected void paintComponent(Graphics g) { // No need to widen it to public
Graphics2D g2 = (Graphics2D)g;
AffineTransform oldTransform = g2.getTransform();
try {
float zoom = 0.5f; // shrink
// Note that transforms are in reverse order
// because of how matrix multiplications work.
AffineTransform newTransform = new AffineTransform();
// 2nd transform: re-center
newTransform.translate(getWidth() * (1 - zoom) / 2,
getHeight() * (1 - zoom) / 2);
// 1st transform: zoom (relative to upper-left corner)
newTransform.scale(zoom, zoom);
g2.transform(newTransform);
// Draw here
} finally {
// Try-finally is probably not required, but ensures that the transform
// gets restored even if an exception is thrown during drawing.
g2.setTransform(oldTransform);
}
I am currently working on an animation to compare two stock exchange algorithms. I am running the algorithms within the paint component extending JComponent. (not the best, but I don't care) I need to have the screen refresh half way through the paint component. I do not want it to have to get all the way through before it up dates the screen. The reason being is I have one algorithm with a nested while loop and the other without. How would I go about doing this?
public void paintComponent(Graphics g) {
//calls in the super class and calls the calibrate the graphics method
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
calibrateFrame( getHeight(), getWidth() );
//Clears the rectangle to avoid overlaying, makes it black
g2D.clearRect(0, 0, getWidth(), getHeight());
g2D.setColor(Color.BLACK);
g2D.fillRect(0, 0, getWidth(), getHeight());
//Draws the rectangles without the algorithm started
redraw(g2D, -1);
/**
*algorithms
*/
fastSpans[0] = 1;
slowSpans[0] = 1;
//Makes a new stack pushes 0 on the stack
Stack myStack = new Stack();
myStack.push(0);
//If it has not been sorted or paused, continue the algorithm
if (!(pause) && !(sorted)){
//The slower algorithm needs to start out at zero (j)
int j = indexValue-1;
g2D.setColor(Color.BLUE);
//Calculates the values for the X and Y coordinates for the
//new rectangle, along with the height
int slowY = calSlowY(j);
int slowX = calSlowX(j);
int curHeightSlow = (int) ((stocks[j]/maxStockValue)*maxHeight);
//Here is the actual algorithm
int k = 1;
boolean span_end = false;
//Nested While Loop
while (((j-k)>0) && !span_end){
if (stocks[j-k] <= stocks[j]){
k = k + 1;
// Draw the current component
// **********************
// DO REFRESH MID PAINT COMPONENT
}
else{ span_end = true; }
}
slowSpans[j] = k;
g2D.setColor(Color.WHITE);
for(int i = 0; i < numberOfStock ; i++){
}
if (!(indexValue >= numberOfStock)){
while (!( myStack.empty()) && (stocks[(int)myStack.peek()]) <= stocks[indexValue]){
myStack.pop();
}
if (myStack.empty()){
fastSpans[indexValue] = indexValue + 1;
}
else {
fastSpans[indexValue]= indexValue - (int) myStack.peek();
//System.out.println("Im in the else");
}
myStack.push(indexValue);
}
}
drawStrings(g2D);
}
I am running the algorithms within the paint component extending JComponent. (not the best, but I don't care)
But you should care, since this impacts on your problem and possible solution.
I need to have the screen refresh half way through the paint component. I do not want it to have to get all the way through before it up dates the screen. The reason being is I have one algorithm with a nested while loop and the other without. How would I go about doing this?
Then don't run the algorithm through paintComponent. Instead use a SwingWorker<Void, Image>, update a BufferedImage and pass that image to the GUI through the worker's publish/process method pair, calling repaint() at the same time. For more on how to use a SwingWorker, please have a look at: Lesson: Concurrency in Swing
Don't understand what half way means.
If it means half of the component, then the simple way is to using two JComponent.
If u means in same component one line updated but another line not updated.
What I understand the repaint is calling when it packs(), updateUI(), or caused by invalidate().
So in my view, the repaint() should only care about paint these lines/2D, and in another thread to execute these loops/generate these data. Once the data collection is finished just call updateUI()/paintImmediately.
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
repaint();
}
});
First off I would like to say that I understand I am asking a lot so any help would be appreciated and I thank you for your time. I am extremely grateful.
Anyway I am creating a game for my A2 coursework, most commonly known as Checkers. I have completed my code and everything works as I had planned except that the CheckerBoard itself as well as the checkerpieces do not appear to be showing.
The section of were my board should be present is just a black space. Although my board does not appear to be displaying, all of the actions I perform on it such as clicking certain section produces the planned response, and although I've checked through my code I cannot work out what I've done wrong.
Anyway if anyone could possibly spot my mistake or perhaps give me some advice I would be extremely grateful. Thank you
As I of course can't upload my entire code I will do snippets of where I think the problem might lie or just important sections. Thank you
CheckerBoard content = new CheckerBoard(); // Sets the CheckerBoard values into the content to be used in the next line
application.setContentPane(content); // Container holds the values together, Content pane of the CheckerBoard
application.pack(); // Use preferred size of content to set size of application.
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
application.setLocation( (screensize.width - application.getWidth())/2,
(screensize.height - application.getHeight())/2 );
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); // Sets so that the application can be exited when the application is closed
application.setResizable(false); // This makes it so that the user can't change the application's size.
application.setVisible(true); // Sets it so that the application can actually be seen
The code above is placed within a "public static void main(String[] args)"
Then below that I have:
public CheckerBoard() {
// This is going to be a constructor, this constructor will set the layout manager for the panel to be null, it will then add components to the panel
// and it will set their bounds.
setLayout(null); // So that it will match my requirement specification, I will do the layout myself
setBackground(new Color(0,120,0)); // Dark Green Background colour.
setPreferredSize(new Dimension(350,250)); // The size of the Panel
BoardComplete checkerboardData = new BoardComplete();
add(checkerboardData); // This will create the components and add them to the content pane
add(NewGameButton);
add(ResignButton);
add(MessageDisplay);
// I will now have to produce a method to set the position and size of each component by calling its setBounds() method
checkerboardData.setBounds(20,20,164,164); // Sets the board dimensions
NewGameButton.setBounds(210, 60, 120, 30);
ResignButton.setBounds(210, 120, 120, 30);
MessageDisplay.setBounds(20, 200, 350, 30);
}
And then finally I have a another public class called BoardComplete which contains all the relevant code involving the actionlistners ect. used:
BoardComplete() {
setBackground(Color.BLACK);
addMouseListener(this);
ResignButton = new JButton("Resign");
ResignButton.addActionListener(this);
NewGameButton = new JButton("New Game");
NewGameButton.addActionListener(this);
MessageDisplay = new JLabel("",JLabel.CENTER);
MessageDisplay.setFont(new Font("Serif", Font.BOLD, 14));
MessageDisplay.setForeground(Color.green);
checkerboardData = new DataForCheckers();
MakeaNewGame();
}
I understand that this is a lot to ask but any help would be greatly appreciate and I would be extremely grateful. Thank you.
Edit due to comment: This is the code for my Paint Class:
public void PaintCheckerBoard(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// This will draw a two-pixel black border around the edges of the canvas.
g.setColor(Color.black);
g.drawRect(0,0,getSize().width-1,getSize().height-1);
g.drawRect(1,1,getSize().width-3,getSize().height-3);
// Draw the squares of the checkerboard and the checkers.
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if ( row % 2 == col % 2 )
g.setColor(Color.LIGHT_GRAY);
else
g.setColor(Color.GRAY);
g.fillRect(2 + col*20, 2 + row*20, 20, 20);
switch (checkerboardData.PieceLocation(row,col)) {
case DataForCheckers.RED:
g.setColor(Color.RED);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
break;
case DataForCheckers.BLACK:
g.setColor(Color.BLACK);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
break;
case DataForCheckers.RED_KING:
g.setColor(Color.RED);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
g.setColor(Color.WHITE);
g.drawString("K", 7 + col*20, 16 + row*20);
break;
case DataForCheckers.BLACK_KING:
g.setColor(Color.BLACK);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
g.setColor(Color.WHITE);
g.drawString("K", 7 + col*20, 16 + row*20);
break;
}
}
}
// If there is a game in progress, highlight the legal moves that the player can make.
// It can be seen that in this process, LegalMoves is never null while a game is in progress
if (CheckerMatchInProgress) {
/* First, draw a 2-pixel cyan border around the pieces that can be moved. */
g.setColor(Color.cyan);
for (int i = 0; i < LegalMoves.length; i++) {
g.drawRect(2 + LegalMoves[i].fromCol*20, 2 + LegalMoves[i].fromRow*20, 19, 19);
g.drawRect(3 + LegalMoves[i].fromCol*20, 3 + LegalMoves[i].fromRow*20, 17, 17);
}
// If a piece is selected to be moved, for example if ChosenRow>=0, then
// draw a 2-pixel white border around that piece, and draw a green border
// around each square that the piece can be legally moved to.
if (ChosenRow >= 0) {
g.setColor(Color.white);
g.drawRect(2 + ChosenColumn*20, 2 + ChosenRow*20, 19, 19);
g.drawRect(3 + ChosenColumn*20, 3 + ChosenRow*20, 17, 17);
g.setColor(Color.green);
for (int i = 0; i < LegalMoves.length; i++) {
if (LegalMoves[i].fromCol == ChosenColumn && LegalMoves[i].fromRow == ChosenRow) {
g.drawRect(2 + LegalMoves[i].toCol*20, 2 + LegalMoves[i].toRow*20, 19, 19);
g.drawRect(3 + LegalMoves[i].toCol*20, 3 + LegalMoves[i].toRow*20, 17, 17);
}
}
}
}
} // end PaintCheckerBoard()
So looking through your code on the other site, your custom paint method never seems to be getting called from anywhere. You're supposed to override the paintComponent method from the Component class (JPanel is a subclass of Component). This paintComponent method will be called whenever swing thinks, or is told to redraw something.
So, add this code to your BoardComplete class:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
PaintCheckerBoard(g);
}
super.paintComponent will do anything swing would do to paint this component (which at this point is just drawing the background). And then you pass the Graphics object to your own custom paint method, that method will draw your entire game on the Graphics object, and swing will display whatever is drawn on there for you.
So now you have to remember also to call repaint() every time something in your game changes. The repaint() method will just tell swing he should repaint something (note: this tells the awt thread it should repaint the component, so it happens asynchronously from where youre calling repaint()).
If youre still confused, you should probably look up some information or tutorials on how to draw with awt/swing using this method.
I've created a custom swing component. I can see it (the grid from the paint method is drawn), but the buttons that are added (verified by println) aren't shown. What am I doing wrong?
Background information: I'm trying to build a tree of visible objects like the Flash/AS3 display list.
public class MapPanel extends JComponent { // or extends JPanel, same effect
private static final long serialVersionUID = 4844990579260312742L;
public MapPanel(ShapeMap map) {
setBackground(Color.LIGHT_GRAY);
setPreferredSize(new Dimension(1000,1000));
setLayout(null);
for (Layer l : map.getLayers()) {
// LayerView layerView = new LayerView(l);
// add(layerView);
System.out.println(l);
JButton test = new JButton(l.getName());
add(test);
validate();
}
}
#Override
protected void paintComponent(Graphics g) {
// necessary?
super.paintComponent(g);
// background
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
// grid
g.setColor(Color.GRAY);
for (double x = 0; x < getWidth(); x += 10) {
g.drawLine((int)x, 0, (int)x, getHeight());
}
for (double y = 0; y < getHeight(); y += 10) {
g.drawLine(0, (int)y, getWidth(), (int)y);
}
}
}
Setting null as the layout manager and then adding buttons will not have any effect. A layout manager is responsible for computing the bounds of the children components, and setting layout manager to null effectively leaves all your buttons with bounds = (0,0,0,0).
Try calling test.setBounds(10, 10, 50, 20) as a quick test to see if the buttons appear. If they do, they will be shown at exactly the same spot. From there you can either install a custom layout manager that gives each button the required bounds, or use one of the core / third party layout managers.
It would be easier for us to diagnose your problem if you gave us a SSCCE. As it stands, we may not have enough information to fix your problem.
I can see it (the grid from the paint
method is drawn),
I don't know what that means, there is no paint() method in the posted code. (But I suppose it is easy enough to assume that you meant paintComponent(g))
However, it looks like the problem is that you are uisng a "null layout". The children will not paint unless you manually set the size and location of the children.
You should probably read a quick tutorial on LayoutManagers. It may make things easier for you when drawing components.