I have a player that can move when pressing the arrow keys. I would like to prevent the user to press multiple arrows at the same time.
This what I have tried:
boolean[] pressedKeys = new boolean[4];
canvas.setOnKeyPressed(event -> {
if (!Arrays.asList(pressedKeys).contains(true)){
if (event.getCode() == KeyCode.UP){
pressedKeys[0] = true;
} else if (event.getCode() == KeyCode.RIGHT){
pressedKeys[1] = true;
} else if (event.getCode() == KeyCode.DOWN){
pressedKeys[2] = true;
} else if (event.getCode() == KeyCode.LEFT){
pressedKeys[3] = true;
}
}
});
canvas.setOnKeyReleased(event -> {
if (event.getCode() == KeyCode.UP){
pressedKeys[0] = false;
} else if (event.getCode() == KeyCode.RIGHT){
pressedKeys[1] = false;
} else if (event.getCode() == KeyCode.DOWN){
pressedKeys[2] = false;
} else if (event.getCode() == KeyCode.LEFT){
pressedKeys[3] = false;
}
});
But it does not work, here I can still press the right and the up arrows for example.
Thanks for any help
I'd create an event handler implementation like this:
class InputHandler implements EventHandler<KeyEvent> {
final private Set<KeyCode> activeKeys = new HashSet<>();
#Override
public void handle(KeyEvent event) {
if (activeKeys.isEmpty() && KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
activeKeys.add(event.getCode());
} else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {
activeKeys.remove(event.getCode());
}
}
public Set<KeyCode> getActiveKeys() {
return Collections.unmodifiableSet(activeKeys);
}
}
The check activeKeys.isEmpty() ensures that we don't register a new keypress until a prior key is released.
A single value for the activeKey could be used instead of the activeKeys HashSet, I just adapted this from a prior solution which works in a more general case.
To use it:
InputHandler inputHandler = new InputHandler();
scene.setOnKeyPressed(inputHandler);
scene.setOnKeyReleased(inputHandler);
Then, if it is something like a game where the input is checked on each frame update of an AnimationTimer, in the update method you can check the current active keys for the frame and action them, like this:
private AnimationTimer createGameLoop() {
return new AnimationTimer() {
public void handle(long now) {
update(now, inputHandler.getActiveKeys());
if (isGameOver()) {
this.stop();
}
}
};
I am not sure if your chosen strategy will result in a desirable user experience, you will need to try it out and see how well it works in your application.
I found a solution, thanks to #kleopatra
This is what I made:
boolean pressedKeys = false, releasedKeys = true;
canvas.setOnKeyPressed(event -> {
if (releasedKeys){
// Code goes here
pressedKeys = true;
releasedKeys = false;
}
});
canvas.setOnKeyReleased(event -> {
if (pressedKeys){
pressedKeys = false;
releasedKeys = true;
}
});
Like this, its not possible to press multiple keys at one time
Related
i have a issue here.
I have a check box and i need to know his true value i think this always return true even if the checkbox is unchecked. What would better way to do this?
private bool _marketingInfo;
public bool MarketingInfo(Checkbox checkbox)
{
if (checkBoxMarketing.IsChecked)
{
_marketingInfo = true;
}
else
{
_marketingInfo = false;
}
return _marketingInfo = true;
}
public bool MarketingInfo(Checkbox checkbox)
{
return checkBoxMarketing.IsChecked
}
Is there a way to multi-select in a Windows Tree View? Similar to the image below
I know that .NET currently doesn't have a multiselect treeview. It is treated as a wrapper around the win32 native treeview control. I would like to avoid the Treeview's Checkbox property if possible. Any suggestions is greatly appreciated!
Im gonna assume you're trying to avoid check boxes. Here is an example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
treeView1.DrawMode = OwnerDrawText;
treeView1.DrawNode += treeView1_DrawNode;
treeView1.NodeMouseClick += treeView1_NodeMouseClick;
}
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) {
// Show checked nodes with an underline
using (SolidBrush br = new SolidBrush(e.Node.TreeView.BackColor))
e.Graphics.FillRectangle(br, e.Node.Bounds);
Font nodeFont = e.Node.NodeFont;
if (nodeFont == null) nodeFont = e.Node.TreeView.Font;
if (e.Node.Checked) nodeFont = new Font(nodeFont, FontStyle.Underline);
using (SolidBrush br = new SolidBrush(e.Node.TreeView.ForeColor))
e.Graphics.DrawString(e.Node.Text, nodeFont, br, e.Bounds);
if (e.Node.Checked) nodeFont.Dispose();
}
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) {
if (Control.ModifierKeys == Keys.Shift && e.Node.Parent != null) {
// Extend selection
bool check = false;
foreach (TreeNode node in e.Node.Parent.Nodes) {
if (node.Checked) check = true;
node.Checked = check;
if (node == e.Node) break;
}
}
else {
unselectNodes(treeView1.Nodes);
e.Node.Checked = true;
}
}
This question has been answered here but I'll briefly answer your question. While it is true that Native Treeview control does not allow multiple selection, you can derive a subclass from it and override its behaviors.
Example code:
checkNodes method:
private void checkNodes(TreeNode node, bool check)
{
foreach (TreeNode child in node.Nodes)
{
if (child.Checked == true)
{
MessageBox.Show(child.Text);
}
//MessageBox.Show(child.Text);
checkNodes(child, check);
}
}
Treeview method after check:
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action != TreeViewAction.Unknown)
{
if (busy) return;
busy = true;
try
{
TreeNode _node = e.Node;
checkNodes(e.Node, e.Node.Checked);
if (e.Node.Checked)
{
MessageBox.Show(e.Node.Text);
}
}
finally
{
busy = false;
}
}
}
It is not trivial to do so, however it can be done.
I need to create a gtk.Entry which accepts only numbers. but I can't overwrite the key_press_event event in an heredited class. It only works if I use the original Entry by means of connect function.
What am I doing wrong?
using Gtk;
public class NumberEntry : Entry {
public void NumberEntry(){
add_events (Gdk.EventMask.KEY_PRESS_MASK);
}
//With customized event left entry editing is not possible
public override bool key_press_event (Gdk.EventKey event) {
string numbers = "0123456789.";
if (numbers.contains(event.str)){
return false;
} else {
return true;
}
}
}
public class Application : Window {
public Application () {
// Window
this.title = "Entry Issue";
this.window_position = Gtk.WindowPosition.CENTER;
this.destroy.connect (Gtk.main_quit);
this.set_default_size (350, 70);
Grid grid = new Grid();
grid.set_row_spacing(8);
grid.set_column_spacing(8);
Label label_1 = new Label ("Customized Entry, useless:");
grid.attach (label_1,0,0,1,1);
//Customized Entry:
NumberEntry numberEntry = new NumberEntry ();
grid.attach(numberEntry, 1, 0, 1, 1);
Label label_2 = new Label ("Working only numbers Entry:");
grid.attach (label_2,0,1,1,1);
//Normal Entry
Entry entry = new Entry();
grid.attach(entry, 1, 1, 1, 1);
this.add(grid);
//With normal Entry this event works well:
entry.key_press_event.connect ((event) => {
string numbers = "0123456789.";
if (numbers.contains(event.str)){
return false;
} else {
return true;
}
});
}
}
public static int main (string[] args) {
Gtk.init (ref args);
Application app = new Application ();
app.show_all ();
Gtk.main ();
return 0;
}
The key_press_event of the superclass is no longer being called. You need to call the base class and return true when you have consumed the key.
public override bool key_press_event (Gdk.EventKey event) {
string numbers = "0123456789.";
if (numbers.contains(event.str)){
return base.key_press_event (event);
} else {
return true;
}
}
If you return false in a signal, this can be passed to an alternate handler, but only if you use connect and not override the signal method.
I have a RadPageview in Strip Mode and I want my program to had support a right-to-left language. When I changing the Right-to-Left Property to true it works fine. but when I run my program and use Arrow Keys (Left or Right) it doesn't work correctly. Left key goes to Right and Right key goes to Left. How can I fix it?
Telerik answered my question:
http://www.telerik.com/forums/right-to-left-arrow-keys-problem
the possible solution that I can suggest is to create a custom RadPageViewStripElement and override its IsNextKey and IsPreviousKey methods on a way to reverse the previous/next navigation as follows:
public class CustomPageView : RadPageView
{
public override string ThemeClassName
{
get
{
return typeof(RadPageView).FullName;
}
}
protected override RadPageViewElement CreateUI()
{
switch (this.ViewMode)
{
case PageViewMode.Strip:
return new CustomRadPageViewStripElement();
default:
return base.CreateUI();
}
}
}
public class CustomRadPageViewStripElement : RadPageViewStripElement
{
public CustomRadPageViewStripElement()
{
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadPageViewStripElement);
}
}
protected override bool IsNextKey(Keys key)
{
if (this.RightToLeft)
{
if (key == Keys.Left)
{
return true;
}
else
{
return false;
}
}
return base.IsNextKey(key);
}
protected override bool IsPreviousKey(Keys key)
{
if (this.RightToLeft)
{
if (key == Keys.Right)
{
return true;
}
else
{
return false;
}
}
return base.IsPreviousKey(key);
}
}
I fix it programmatically by using ProcessCmdKey of form.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Right))
{
int x = radPageView1.Pages.IndexOf(this.radPageView1.SelectedPage) - 1;
if (x < 0)
x = radPageView1.Pages.Count() - 1;
else if (x >= radPageView1.Pages.Count())
x = 0;
radPageView1.SelectedPage = radPageView1.Pages[x];
return true;
}
else if(keyData == Keys.Left)
{
int x = radPageView1.Pages.IndexOf(this.radPageView1.SelectedPage) + 1;
if (x <= 0)
x = radPageView1.Pages.Count() - 1;
else if (x >= radPageView1.Pages.Count())
x = 0;
radPageView1.SelectedPage = radPageView1.Pages[x];
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
how do you stop your program from generating JFrames after you press a JButton? I am trying to make it stop generating new JFrames after the first button press but sadly, this isn't happening. Any help would be greatly appreciated. Thank you.
list.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
for (int counter=0; counter<1; counter++){
if (counter<1){
Newbox fresh = new Newbox();
}
if (counter >1) {
break;
}
}
}
});
You could just use a boolean variable to stop it from creating a new frame. something like
boolean pressed = false;
list.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
for (int counter=0; counter<1; counter++){
if (counter<1 && pressed == false){
Newbox fresh = new Newbox();
pressed = true;
}
if (counter >1) {
break;
}
}
}
});
Trx to add a boolean.
Boolean pressed = false;
list.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
if (!pressed){
Newbox fresh = new Newbox();
pressed = true;
}
}
});
I tried using booleans but this approach ended up working better so for the record, this is one way to solve this. Thank you all for the feedback.
list.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
Newbox fresh = new Newbox();
((AbstractButton)e.getSource()).setEnabled(false);
}
});