Initializing a grid of JButton and adding them to a JFrame - arrays

I'm trying to write a program that plays Yahtzee in a JFrame. Our teacher has a way we're supposed to write it, and it involves adding ConfigurationButtons - a class that extends JButton - to the JFRame. Here is the code I have so far:
builder= new PlayerPanel();
manager = new JFrame("Yahtzee!");
manager.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
manager.setLayout(new GridLayout(TOTAL, numPlayers));
manager.add(builder);
//manager.add(howManyPlayers);
manager.setSize(1200,600);
manager.setVisible(true);
private class PlayerPanel extends JPanel
{
private final int ROWS = 18;
private JLabel[]titles;
private PlayerPanel()
{
for(int j=0;j<numPlayers;j++)
{
for(int i=0;i<ROWS;i++)
{
fields[i][j]=new ConfigurationButton(i,j);
manager.add(fields[i][j]);
}
}
}
I tried implementing this solution but it didn't work- all I get is a blank JFrame.

OK, to fill out your JFrame, see what I have done with the following code, and apply it to your situation.
JFrame manager = new JFrame("Manager");
JPanel panel = new JPanel(new GridLayout(10, 10));
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
JButton button = new JButton(i + " - " + j);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
((JButton)(e.getSource())).setText("Clicked");
}
});
panel.add(button);
}
}
manager.add(panel);
manager.setSize(750, 750);
manager.setVisible(true);
Take note of how the panel is set up in a GridLayout (as you had), but the panel is then added to the JFrame.
You should be able to build your panel based off this example, substituting your custom components where necessary.

Related

Unknown size of TextFields Array JavaFX

I am trying to build a GUI stack using JavaFX. I am supposed to ask the user how many elements he wants for the stack. Then the number of text fields should appear on the right screen (based on the size of user's entry). I have been trying all day in vain.
Here is what I have been trying to do so far. Once I solve TextFields array issue, I should complete my program.
public class StackGUI extends Application {
private Button push, pop, peek, empty, create, build;
private TextField[] data;
private TextField size, numberText;
private Label sizeLabel, numberLabel;
private int sizeOfStack;
String sizeDialog = "0";
#Override
public void start(Stage primaryStage) {
BorderPane border = new BorderPane();
// Buttons
push = new Button("PUSH");
push.setPrefSize(150, 50);
pop = new Button("POP");
pop.setPrefSize(150, 50);
peek = new Button("PEEK");
peek.setPrefSize(150, 50);
empty = new Button("EMPTY");
empty.setPrefSize(150, 50);
FlowPane bottom = new FlowPane();
bottom.setHgap(10);
bottom.setAlignment(Pos.CENTER);
bottom.getChildren().addAll(push, pop, peek, empty);
border.setBottom(bottom);
//Center
VBox center = new VBox(5);
center.setAlignment(Pos.CENTER);
size = new TextField();
size.setMaxWidth(200);
size.setEditable(false);
numberLabel = new Label("Enter a number: ");
numberText = new TextField();
numberText.setMaxWidth(200);
//sizeLabel = new Label("How many numbers? ");
create = new Button("Create a stack");
create.setPrefWidth(200);
build = new Button("Build the stack");
build.setPrefWidth(200);
build.setDisable(true);
center.getChildren().addAll(create, size, build);
border.setCenter(center);
//Stack TextFields --> right
create.setOnAction(ae -> {
TextInputDialog input = new TextInputDialog();
input.setContentText("How many Numbers");
input.setHeaderText("Size Of Stack");
input.setTitle("Stack");
input.showAndWait();
size.setAlignment(Pos.CENTER);
size.setText("Number Of Elements: " + input.getEditor().getText());
sizeDialog = input.getEditor().getText();
build.setDisable(false);
});
sizeOfStack = Integer.parseInt(sizeDialog);
data = new TextField[sizeOfStack];
HBox right = new HBox(5);
build.setOnAction(ae -> {
create.setDisable(true);
numberText.setPromptText("Enter a number to push");
center.getChildren().addAll(numberLabel, numberText);
for (int i = 0; i < sizeOfStack; i++) {
data[i] = new TextField();
right.getChildren().add(data[i]);
}
});
border.setRight(right);
//Scene
Scene scene = new Scene(border, 800, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("Stack");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
As #James_D pointed out, you need to move sizeOfStack = Integer.parseInt(sizeDialog); inside of build.setOnAction. You also need to move data = new TextField[sizeOfStack] ;.
I also moved HBox right = new HBox(sizeOfStack); and border.setRight(right);, but that may not have been necesary.
Code:
build.setOnAction((ActionEvent event) - > {
sizeOfStack = Integer.parseInt(sizeDialog);
data = new TextField[sizeOfStack];
create.setDisable(true);
numberText.setPromptText("Enter a number to push");
center.getChildren().addAll(numberLabel, numberText);
HBox right = new HBox(sizeOfStack);
for (int i = 0; i < sizeOfStack; i++) {
TextField text = new TextField();
data[i] = text;
right.getChildren().add(data[i]);
}
border.setRight(right);
});

No animation with snapToGrid scrolling and tensileDragEnabled set to false

I tried out snapToGrid which I thought might be just the simple solution one wants for lists with side-swipeable entries.
But if I disable tensileDragEnabled then there is no animation when the row snaps to the grid.
Is there a way to disable the tensile scrolling on the X-axis whilst having snapToGrid still animated?
Here's the code:
public class FormScrollingXY extends Form {
public FormScrollingXY() {
setTitle("FormScrollingXY");
setScrollable(false);
setScrollableY(true);
setLayout(new BoxLayout(BoxLayout.Y_AXIS));
for (int rowIndex = 0; rowIndex < 50; rowIndex++) {
Container containerRow = new Container(new BoxLayout(BoxLayout.X_AXIS));
containerRow.setSnapToGrid(true);
containerRow.setScrollableX(true);
containerRow.setTensileDragEnabled(false); // bad behaviour
for (int columnIndex = 0; columnIndex < 3; columnIndex++) {
Container containerColumn = new Container(new FlowLayout()) {
#Override
protected Dimension calcPreferredSize() {
Dimension dimension = new Dimension(super.calcPreferredSize());
dimension.setWidth(containerRow.getWidth());
return dimension;
}
};
containerColumn.add(new Label((rowIndex + 1) + "/" + (columnIndex + 1)));
containerRow.add(containerColumn);
}
add(containerRow);
}
}
}
This is a guess but try doing this to see if it works around this:
Container containerRow = new Container(new BoxLayout(BoxLayout.X_AXIS)) {
public boolean isScrollableY() {
return false;
}
};

Movieclip not being removed from array or stage - AS3 - CS6

my enemy movie clips are not being removed from the stage on collision/hitTestObject with the bullet movie clip, the bullets are being removed though, only the enemies that are not. Appreciate all help with this. Thanks you guys, your a brilliant community here, respect you loads.
I used the same code that made the bullet movie clips be removed for the enemies (though change changing the vars etc accordingly).
My code for Main.as and Enemy.as is here:
Main.as
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends MovieClip
{
public var player:Player;
public var enemy:Enemy;
public var bulletList:Array = [];
public var mousePressed:Boolean = false; //keeps track of whether the mouse is currently pressed down
public var delayCounter:int = 0; //this adds delay between the shots
public var delayMax:int = 7; //change this number to shoot more or less rapidly
public var enemies:Array = [];
public function Main():void
{
player = new Player(stage, 320, 240);
stage.addChild(player);
//stage.addEventListener(MouseEvent.CLICK, shootBullet, false, 0, true); //remove this
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, 0, true);
stage.addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
for(var numBaddies=0; numBaddies<6;numBaddies++){
var enemy:Enemy = new Enemy(null);
enemy.x = numBaddies*50;
enemy.y = numBaddies*50
stage.addChild(enemy);
enemies.push(enemy);
}
}
public function loop(e:Event):void
{
if(mousePressed) // as long as the mouse is pressed...
{
delayCounter++; //increase the delayCounter by 1
if(delayCounter == delayMax) //if it reaches the max...
{
shootBullet(); //shoot a bullet
delayCounter = 0; //reset the delay counter so there is a pause between bullets
}
}
if(bulletList.length > 0)
{
for(var i:int = bulletList.length-1; i >= 0; i--)
{
bulletList[i].loop();
}
}
for(var h = 0; h<bulletList.length; ++h)
{
if(bulletList[h].hitTestObject(this)){
trace("player hit by baddie " + h);
}
}
for(var u:int=0; u<enemies.length; u++) {
Enemy(enemies[u]).moveTowards(player.x, player.y);
}
}
public function mouseDownHandler(e:MouseEvent):void //add this function
{
mousePressed = true; //set mousePressed to true
}
public function mouseUpHandler(e:MouseEvent):void //add this function
{
mousePressed = false; //reset this to false
}
public function shootBullet():void //delete the "e:MouseEvent" parameter
{
var bullet:Bullet = new Bullet(stage, player.x, player.y, player.rotation, enemies);
bullet.addEventListener(Event.REMOVED_FROM_STAGE, bulletRemoved, false, 0, true);
bulletList.push(bullet);
stage.addChild(bullet);
}
public function bulletRemoved(e:Event):void
{
e.currentTarget.removeEventListener(Event.REMOVED_FROM_STAGE, bulletRemoved);
bulletList.splice(bulletList.indexOf(e.currentTarget),1);
}
}
}
Enemy.as
package {
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
public class Enemy extends MovieClip {
public var bullets:Array;
public var stageRef:Stage;
private var enemyPositionX, enemyPositionY,xDistance,yDistance,myRotation:int;
public function Enemy(bulletList:Array) {
// constructor code
bullets = bulletList;
}
public function moveTowards(playerX:int, playerY:int){
xDistance = this.x - playerX;
yDistance = this.y - playerY;
myRotation = Math.atan2(yDistance, xDistance);
this.x -= 3 * Math.cos(myRotation);
this.y -= 3 * Math.sin(myRotation);
}
public function loop():void{
for(var i=0; i<bullets.length; ++i)
{
if(bullets[i].hitTestObject(this)){
trace("you killed enemy " + i);
removeSelf();
}
}
}
private function removeSelf():void
{
removeEventListener(Event.ENTER_FRAME, loop);
if (stageRef.contains(this))
stageRef.removeChild(this);
}
}
}
And for reference so you can see how I used the same code to remove the movie clips, I'll add the Bullet.as too:
Bullet.as
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
public class Bullet extends MovieClip
{
private var stageRef:Stage; //checks if the bullet leaves the screen borders
private var speed:Number = 10; //speed that the bullet will travel at
private var xVel:Number = 0; //current x velocity
private var yVel:Number = 0; //current y velocity
private var rotationInRadians = 0; //convenient to store our rotation in radians instead of degrees
public var allBaddies:Array;
//our constructor requires: the stage, the position of the bullet, and the direction the bullet should be facing
public function Bullet(stageRef:Stage, X:int, Y:int, rotationInDegrees:Number, enemies:Array):void
{
this.stageRef = stageRef;
this.x = X;
this.y = Y;
this.rotation = rotationInDegrees;
this.rotationInRadians = rotationInDegrees * Math.PI / 180; //convert degrees to radians, for trigonometry
allBaddies = enemies;
}
public function loop():void //we don't need to include the "e:Event" because we aren't using an EventListener
{
for(var b=0; b<allBaddies.length; ++b)
{
if(allBaddies[b].hitTestObject(this)){
trace("bullet hit baddie " + b);
removeSelf();
}
}
xVel = Math.cos(rotationInRadians) * speed; //uses the cosine to get the xVel from the speed and rotation
yVel = Math.sin(rotationInRadians) * speed; //uses the sine to get the yVel
x += xVel; //updates the position
y += yVel;
//if the bullet goes off the edge of the screen...
if(x > stageRef.stageWidth || x < 0 || y > stageRef.stageHeight || y < 0)
{
this.parent.removeChild(this); //remove the bullet
}
}
private function removeSelf():void
{
removeEventListener(Event.ENTER_FRAME, loop);
if (stageRef.contains(this))
stageRef.removeChild(this);
}
}
}
Ok there are a couple of things I would change around, alongside a couple issues I noticed.
First, your Enemy class as far as I can tell never gets the stageRef variable set. Therefore in your Enemy class removeSelf() your stageRef will be null.
You can either pass the stage in through the constructor and set it (as you do in your bullet class), or you can set it after you instantiate in your enemies loop with enemy.stageRef = stage. Or you can add and event listener to your enemy class for Event.ADDED_TO_STAGE and when that happens your enemy will have a reference to the stage inherited.
Now, the real meat of the matter. You have 2 for loops testing for collision (aside from one in your Main class too, but I'll get to that). One is in your bullet class and one is in your enemy class. This is overkill and is difficult on performance if you start adding in lots of bullets and enemies. You really only need a single for loop (like the one in your bullet class), and when it detects a collision it calls the collided objects remove method. That would look something like this in your Bullet class:
public function loop():void //we don't need to include the "e:Event" because we aren't using an EventListener
{
for(var b=0; b<allBaddies.length; ++b)
{
if(allBaddies[b].hitTestObject(this)){
trace("bullet hit baddie " + b);
removeSelf();
allBaddies[b].removeSelf();
}
}
Although, for this to work you would need to set the removeSelf() in your Enemy class access to public:
public function removeSelf():void
{
//this is removing a listener not even added Enemy...
//removeEventListener(Event.ENTER_FRAME, loop);
if (stageRef.contains(this))
stageRef.removeChild(this);
}
Then you can probably even eliminate your loop() from the Enemy class seeing as how all it does it detect collisions that will no longer be necessary.
Lastly as to why this might happened? Well it could be the bullet hitTest which is running first from your call in the main class: bulletList[i].loop(); This hitTest is being detected, then removing the bullet leaving your Enemy class without an object to hit test against. BUT! you are not calling the loop() from enemy anywhere in your main class, therefore that hit test will never run.
It's best to condense your collisions down. You are currently looping through your Bullet instances in the main class, calling their loop() (which tests for collisions), and then afterwards doing a for loop doing the collision test again. You could change this:
if(bulletList.length > 0)
{
for(var i:int = bulletList.length-1; i >= 0; i--)
{
bulletList[i].loop();
}
}
//this is no longer needed...
/*for(var h = 0; h<bulletList.length; ++h)
{
if(bulletList[h].hitTestObject(this)){
trace("player hit by baddie " + h);
}
}*/
There is no reason to test the collision in the Bullet class AND in the Main class loop(e:Event).
Hope this information helps! Good luck :)

How to duplicate a custom control (panel) programmatically

I am using C# in VS 2010. I created a custom panel and would like to add this custom panel 9 times so I created a loop to add a copy of the panel 9 times at equal distance from each other. Each panel will have its own text and image. All I'm getting though is a single panel. Any insight would be appreciated
public partial class Form1 : Form
{
int index = 0;
List<CutePanel.CustomPanel> MenuItems = new List<CutePanel.CustomPanel>();
public Form1()
{
InitializeComponent();
for (int i = 0; i < 9; i++)
{
this.cpTest.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.cpTest.LabelText = "My super click text";
this.cpTest.Location = new System.Drawing.Point(12, 12+(64*i));
this.cpTest.Name = "cpTest";
this.cpTest.Size = new System.Drawing.Size(344, 58);
this.cpTest.SuperClick = null;
this.cpTest.TabIndex = 6;
}
cpTest.MouseClick += new MouseEventHandler(cpTest_MouseClick);
cpTest.SuperClick += new EventHandler(cpTest_SuperClick);
cpTest.LabelText = "This is my text.";
MenuItems.Add(cpTest);
}
void cpTest_SuperClick(object sender, EventArgs e)
{
tcTest.SelectedIndex = index++ % 2;
}
void cpTest_MouseClick(object sender, MouseEventArgs e)
{
tcTest.SelectedIndex = index++ % 2;
}
private void customPanel3_MouseClick(object sender, MouseEventArgs e)
{
tcTest.SelectedIndex = index++ % 2;
}
}
Thanks.
You have to make a distinction between your panel class and panel objects, also called instances of this class. Think of the class as a template that serves in creating objects. These objects are created with the new keyword:
for (int i = 0; i < 9; i++)
{
var cp = new CutePanel.CustomPanel();
cp.BackColor = System.Drawing.SystemColors.ActiveCaption;
cp.LabelText = "My super click text";
cp.Location = new System.Drawing.Point(12, 12+(64*i));
cp.Name = "cpTest" + i;
cp.Size = new System.Drawing.Size(344, 58);
cp.SuperClick = null;
cp.TabIndex = 6;
cp.MouseClick += new MouseEventHandler(cpTest_MouseClick);
cp.SuperClick += new EventHandler(cpTest_SuperClick);
cp.LabelText = "This is my text.";
MenuItems.Add(cp);
}
You can also assign it values from the existing panel:
cp.BackColor = cpTest.BackColor;
cp.Size = cpTest.Size;
...
An elegant way of making a duplicate is to include a Clone method in your panel class
public class CustomPanel
{
...
public CustomPanel Clone()
{
var cp = (CustomPanel)this.MemberwiseClone();
cp.Parent = null; // It has not yet been added to the form.
return cp;
}
}
Then
for (int i = 0; i < 9; i++)
{
CustomPanel cp = cpTest.Clone();
// Now only change the differing properties
cp.Location = new System.Drawing.Point(12, 12+(64*i));
cp.Name = "cpTest" + i;
cp.TabIndex += i + 1;
MenuItems.Add(cp);
}
but attention: If the cloned control is a container control containing other controls, you must clones those recursively as well. I.e., you must perform a deep clone! Creating new controls as shown in my first code snippet is safer.

how to select treeviewitem in wpf

hi everyone! i am new in wpf so forgive me i want more!!!
i am trying to build an application. i have a treeview that bounded a datasource. it is okay. i have two problems. First; how can i select an item from treeview? i wanna a new window popsup when i select an item; when i click another item; another window popsup. Second problem is that i can not change foreground and font.Thanks everyone in advance
namespace CellBiology
{
public partial class TreeView
{
public TreeView()
{
this.InitializeComponent();
BindTreeView();
}
public void BindTreeView()
{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\\CellBiology.mdb;Persist Security Info=True");
try
{
con.Open();
OleDbCommand cmd = new OleDbCommand("Select * from Topics", con);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "Topics");
int row = ds.Tables["Topics"].Rows.Count;
List<MyMenuItem> myList = new List<MyMenuItem>();
if (row > 0)
{
for (int i = 0; i <= row - 1; i++)
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[i][0].ToString()), ds.Tables["Topics"].Rows[i][1].ToString(), 0));
for (int j = 0; j <= row - 1; j++)
{
if (ds.Tables["Topics"].Rows[i][0].ToString() == ds.Tables["Topics"].Rows[j][2].ToString())
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[j][0].ToString()), ds.Tables["Topics"].Rows[j][1].ToString(), Convert.ToInt32(ds.Tables["Topics"].Rows[i][0].ToString())));
for (int k = 0; k <= row - 1; k++)
{
if (ds.Tables["Topics"].Rows[j][0].ToString() == ds.Tables["Topics"].Rows[k][2].ToString())
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[k][0].ToString()),
ds.Tables["Topics"].Rows[k][1].ToString(),
Convert.ToInt32(ds.Tables["Topics"].Rows[j][0].ToString())));
for (int l = 0; l <= row - 1; l++)
if (ds.Tables["Topics"].Rows[k][0].ToString() == ds.Tables["Topics"].Rows[l][2].ToString())
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[l][0].ToString()),
ds.Tables["Topics"].Rows[l][1].ToString(), Convert.ToInt32(ds.Tables["Topics"].Rows[k][0].ToString())));
Dictionary<int, TreeViewItem> flattenedTree = new Dictionary<int, TreeViewItem>();
foreach (MyMenuItem item in myList)
{
TreeViewItem treenode = new TreeViewItem();
treenode.Header = item.TopicName;
treenode.Tag = item;
flattenedTree.Add(item.TopicID, treenode);
if (flattenedTree.ContainsKey(item.TopLevelID))
{
flattenedTree[item.TopLevelID].Items.Add(treenode);
}
else
{
myTreeView.Items.Add(treenode);
}
public class MyMenuItem
{
internal int TopicID { get; set; }
internal string TopicName { get; set; }
internal int TopLevelID { get; set; }
internal MyMenuItem(int topicid, string topicname, int toplevelid)
{
TopicID = topicid;
TopicName = topicname;
TopLevelID = toplevelid;
private void myTreeView_SelectedItemChanged(object sender, RoutedEventArgs e)
{
**how can i code here?**
}
}
}
To change the font:
myWindow.FontFamily = new FontFamily("Font Name");
Where the "Font Name" is the name of known font types, eg. "Times New Roman" or "Comic Sans MS". You can find more usages here.
To Change the foreground color:
myWindow.Foreground = new SolidColorBrush(Colors.Red);
Where Colors.Red is can be any 'pre-defined' color of your choice.
Hope it helps.
To answer your "how can i code here?" specifically, you can do the following to access the TreeViewItem:
TreeViewItem selectedTreeViewItem = ((TreeViewItem)e.NewValue);
Once you've got that you can access the data that that item represents via it's DataContext property like so:
MyDataType myData = (MyDataType)selectedTreeViewItem.DataContext;
To popup the new window you can create an instance of your Window sublass and either use ShowDialog, if you want it to be modal, or Show if you want to allow mulitple windows to be opened at the same time.

Resources