I am currently in the process of turning a sudoku solving program into a GUI with scala.swing and running into some trouble with the use of different functions. That is to say, I have a function for completely solving the puzzle, another for offering a hint entry, and another that will reset the grid. The interface consists of 81 individual ComboBox'es (see: http://i.imgur.com/45vzpei.png) and three buttons that perform said functions. My problem is that, while the separate reactions/cases involved reference specifically which buttons/functions to listen to, any button will incite all of the functions. My code for each of the listeners/buttons looks something like the following
listenTo(solve,comb11,comb12,comb13,comb14,comb15,comb16,comb17,comb18,comb19,comb21,comb22,comb23,comb24,comb25,comb26,comb27,comb28,comb29,comb31,comb32,comb33,comb34,comb35,comb36,comb37,comb38,comb39,comb41,comb42,comb43,comb44,comb45,comb46,comb47,comb48,comb49,comb51,comb52,comb53,comb54,comb55,comb56,comb57,comb58,comb59,comb61,comb62,comb63,comb64,comb65,comb66,comb67,comb68,comb69,comb71,comb72,comb73,comb74,comb75,comb76,comb77,comb78,comb79,comb81,comb82,comb83,comb84,comb85,comb86,comb87,comb88,comb89,comb91,comb92,comb93,comb94,comb95,comb96,comb97,comb98,comb99)
reactions += {
case ButtonClicked(solve) =>
...[working code for solve function]...
}
(The 'comb##'s are the exhaustive 81 ComboBoxes and the 'solve' is the button that solves the whole puzzle.) If I get rid of all but one of the listener/reaction blocks of code, clicking the remaining button works perfectly. If I try to include two or all of the listener/reaction code blocks, then every button causes ALL functions to be performed, which is clearly confusing and undesirable.
Not sure I understand your problem. But if you use lower case names in pattern matching extraction, these are fresh variables, and have nothing to do with values of the same name defined elsewhere. So to react to the solve button, you need to match against the value solve which you can do by putting it in back ticks:
listenTo(allMyButtons: _*)
reactions += {
case ButtonClicked(`solve`) => // note the back ticks!
...[working code for solve function]...
}
Otherwise, why don't you just keep each reaction with each combo box?
val combos = Vector.tabulate(81) { i =>
new ComboBox(1 to 9) {
listenTo(this)
reactions += {
case ButtonClicked(_) =>
... // not important to check the button - we only listen to one!
}
}
}
There is also a shorter way of defining the reaction to a pressed button.
import swing.{MainFrame, FlowPanel, Button}
val frame = new MainFrame {
contents = new FlowPanel {
contents += Button("solve")(println("solve"))
}
visible = true
}
Related
I am attempting to create a search bar using a custom HTML component for predictive text input. The way this component is built, it generates several plain HTML children that I need to act on to get full features. Specifically, I need to execute a blur action on one of the generated elements when the user presses escape or enter.
I got it to work using a ref on the custom component and calling getElementsByClassName on the ref, but using getElementsByClassName does not seem like the best solution. It pierces through the virtual and has odd side effects when testing.
This is a snippet of the component being rendered:
<predictive-input id='header-search-bar-input' type='search'
value={this.state.keywords}
ref={(ref: any) => this.predictiveInput = ref}
onKeyDown={(e: React.KeyboardEvent<any>) => this.handleKeyDown(e)}>
</predictive-input>
and the keyDown handler:
private handleKeyDown(e: React.KeyboardEvent<any>) {
// must access the underlying input element of the kat-predictive-input
let input: HTMLElement = this.predictiveInput.getElementsByClassName('header-row-text value')[0] as HTMLElement;
if (e.key === 'Escape') {
// blur the predictive input when the user presses escape
input.blur();
} else if (e.key === 'Enter') {
// commit the search when user presses enter
input.blur();
// handles action of making actual search, using search bar contents
this.commitSearch();
}
}
The element renders two children, one for the bar itself and one for the predictive dropdown. The classes of the underlying in the first are 'header-row-text' and 'value', so the element is correctly selected, but I am worried that this is violating proper React style.
I am using React 16.2, so only callback refs are available. I would rather avoid upgrading, but if a 16.3+ solution is compelling enough, I could consider it.
If you don't have any control over the input then this is the best approach in my opinion.
It's not ideal, but as you're stuck with a 3rd party component you can only choose from the methods that are available to you. In this case, your only real options are to find the element based on its class, or its position in the hierarchy. Both might change if the package is updated, but if I had to choose which would be more stable, I'd go for className.
I'm surprised I don't know how to do this, but as it turns out I really don't; simply put, I'm trying to make a side-scrolling shooter game, a basic one and in it, I have 50 stars spawned on-screen through a "for" loop upon the game starting. There is a function which does this and a listener is at the beginning. Problem is, when you lose the game and go back to main menu, 50 more stars would be spawned, which isn't what I want. So, I'm trying to make an "if" statement check at the beginning, so that the game checks whether there is an instance/movie clip of the star object/symbol before determining whether the function that spawns stars should be called out with a listener. So, how do I do this? I looked through some other checks and they didn't help as the codes presented were vastly different there and so I'm just getting errors.
Let me know if a better explanation is needed or if you would like to see some of the code. Note that the game overall already has a lot of code, so just giving all of it would probably not be helpful.
I suggest you rethink your approach. You're focusing on whether stars have been instantiated. That's ok but not the most basic way to think about it.
I would do this instead
private function setup():void{
loadLevel(1);
addListeners();
loadMusic();
// etc...
// call all functions that are needed to just get the app up and running
}
private function loadLevel(lev:int):void{
addStars();
// call all functions that are needed each time a new level is loaded
}
private function restartLevel():void{
// logic for restarting level,
// but this *won't* include adding star
// because they are already added
}
There are other ways to do this but this makes more sense to me than your approach. I always break my game functions into smaller bits of logic so they can be reused more easily. Your main workhorse functions should (IMHO) primarily (if not exclusively) just call other functions. Then those functions do the work. By doing it this way, you can make a function like resetLevel by assembling all the smaller functions that apply, while excluding the part about adding stars.
Here's what I did to solve my problem... Here's what I had before:
function startGame():void
{
starsSpawn();
//other code here
}
This is what I changed it to:
starsSpawn();
function startGame():void
{
//other code here
}
when you said existance, so there is a container, i named this container, (which contain stars , and stars was added to it) as starsRoot, which absolutely is a DisplayObject (right?)
now, to checking whole childrens of a DisplayObject, we have to do this :
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
}
then, how to check if that child is really star!?
as you said
whether there is an instance/movie clip of the star
so your stars's type is MovieClip, and they don't have any identifier (name), so how to find them and make them clear from other existing movieclips. my suggestion :
define a Linkage name for stars from library, thats a Class name and should be started with a capital letter, for example Stars
now, back to the code, this time we can check if child is an instance of Stars
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
if (child is Stars) {
// test passed, star exist
break;
}
}
I have an issue with removing old elements from my lists. I tried using the methods clear() and removeAllElements() and removeAll() wherever I could but that does not seem to clear them.
To help you understand the situation a little bit better:
d1 is an ArrayList that contains all available devices in our program.
availList2 and availList3 are using the DefaultListModel.
We wanted to make it so that when the user loads the products from the proper text file, if he did that a second time the products already listed in our gui would be overwritten with the ones in the original text file. However we ended up having duplicates of the products, even though we used the clear() method in both the d1 (ArrayList) and the JList.
Any useful tips or possible causes would be appreciated. Thank you very much in advance.
if(ev.getSource() == load_availables) {
int returnVal = chooser.showOpenDialog(mainApp.this);
if(returnVal == JFileChooser.APPROVE_OPTION) {
d1.returnDevices().removeAll(d1.returnDevices());
availList2.clear();
availList3.clear();
//availList2.removeAllElements();
//availList3.removeAllElements();
File file = chooser.getSelectedFile();
read.ReadDevices(file);
for(int i = 0; i < read.Size(); i++) {
d1.add_AvailableDevices(read.get(i));
}
}
}
If the list is not cleared then I would suggest you don't have the proper reference to the DefaultListModel that is being used by the JList when you invoke the clear() method.
Start by the reading the section from the Swing tutorial on How to Use Lists.
Download the ListDemo code and play with it. Change the "Fire" button to use the clear() method on the DefaultListModel to prove to yourself that is all you need to do.
Once you see the code working then you figure out how your code is different from the ListDemo working version.
I'm making a 2D platformer game and i'm trying to add collisions to the platforms so that when the character hits it it cannot pass through. I'm struggling to find the syntax to use to create this collision. So far this is what I have.
Also i would still like to be able to use hitTestObject within the if statement.
thanks
public function platform1Collision():void
{
if (fireboy1.hitTestObject(Platform1))
{
//fireboy1 cannot pass through
}
}
You'll probably want to prevent fireboy1's y property from extending past Platform1's y property:
function platform1Collision():void
{
if(fireboy1.hitTestObject(Platform1))
{
if(fireboy1.y > Platform1.y)
{
fireboy1.y = Platform1.y + Platform1.height;
}
else
{
fireboy1.y = Platform1.y - fireboy1.height;
}
}
}
NOTE: The above code sample assumes top-left orientation for both fireboy1 and Platform1.
EDITED: The above edited code will allow fireboy1 to walk beneath Platform1, but not pass through it.
This is a very rudimentary example to give you an idea of the type of logic you can use. If you want to allow fireboy1 to pass through Platform1 from below, you'll have to update the logic to allow for that. For example, if you take out the if/else and just automatically place fireboy1 above Platform1 every time they collide, it will appear as if player1 is jumping onto Platform1 when it is approached from below.
Bit of a mystery to me this, but I have a table in libgdx where everything is being positioned in new cells vertically;
I am not using .row() anywhere.
Probably doing something stupid here but I cant see it.
Clues as to what can cause this?
(I'll post the code if needed, but its not that neat, and seeing as I think knowing anything that can cause a newline will help me, it shouldn't necessarily be needed)
edit
Tried to cut the code down to all the bits that happen when an item gets added
Code;
//function that triggers on adding
//SSSNode is a semantic reference for the items details,it just justs made into a label like object
public void addItem(SSSNode itemsnode){
Item newitem = new Item(itemsnode); //Item extends label
allItems.add(newitem);
super.add(newitem).size(60, 30).top().left().fillY().expandY();
//pack();
//super.invalidate();
//super.validate(); (tried doing pack, validate, and none...neither helped)
//update the GUI bar in case the inventory tab isnt there yet
MainExplorationView.usersGUI.setDataVisible(true);
}
The following code is in "usersGUI", which creates and handles the popup called inventory which is whats in the picture and is the table I cant get to behave.
//ensures the interface for the inventory popup is setup and visible
//also refreshes the links
public void setDataVisible(boolean visible){
if (myContents.isVisible!=true){
myContents.isVisible=visible;
refreshlinks();
setupInventory();
}
}
private void refreshlinks() {
super.clearChildren();
super.addActor(backgroundobject);
super.addActor(ME.playersInventory); //re adds the inventory panel table?
int y = 440;
ME.playersInventory.validate(); //revalidated the table (I dumped this almost everywhere in frustration)
//below is not relevant, it updates other items in a onscreen gui
for (InterfaceButton link : allLinks) {
if (link.isVisible==true){
link.setPosition(5,y);
super.addActor(link);
y=y-30;
}
}
backgroundobject.setSize(85, 200);
backgroundobject.setPosition(0,y+20);
}
//ensures inventory is setup once.
public void setupInventory() {
if (setup){
return;
}
Log.info("setupInventory");
ME.playersInventory.setPrefWidth(super.getWidth());
Log.info("width is "+super.getWidth());
ME.playersInventory.setHeight(200);
ME.playersInventory.pack();
float X = myContents.getX();
float Y = myContents.getY()-ME.playersInventory.getHeight();
Log.info("popping up inventory at:"+X+","+Y);
ME.playersInventory.setPosition(X, Y);
super.validate();
setup=true;
}
The full code is also on GitHub;
https://github.com/ThomasWrobel/MeshExplorerGDX
The whole project is a game being made to demo/test and open source distributed semantic database system. The relevant bit is the inventory and the maybe the gui that creates it.
Anyone with good knowledge of LibGDXs workings should I think not need to look any of the code though if theres other things that can tell a table to start a new row. (ie, any layout restrictions that can cause it to happen automatically? )
layout ending the current row was a side effect to make the layout logic simpler. It is now fixed.
Note HorizontalGroup is still a better fit for your use case and has the benefit that you can add/remove actors at any index.
The answer seems to be that layout() causes new rows;
http://www.badlogicgames.com/forum/viewtopic.php?f=11&t=15857&p=68533&hilit=layout#p68533
Adherently this is how its supposed to work, despite the docs not saying that.