Change sequence of states on a three-state ToggleButton - togglebutton

It seems that the out-of-box sequence for a three-state ToggleButton is On, Indeterminate, Off.
I would like to change this to On, Off, Indeterminate; similar to the question presented here .
I've tried modifying my StateChanging event, but I think that will result in an infinite loop.

I briefly implemented a working solution using ToggleStateChanging to change the order of the states, and then using a global variable to avoid an infinite loop. However, I then had a new problem where the ToggleButton had some sort of auto-theme where it was shaded differently for each state and on MouseHover. I didn't want that theme, so I ultimately just changed the buttons to standard buttons, and now I'm using the buttons' Tag property to emulate ToggleState.
My particular solution uses a Telerik RadButton, but this would work for a standard button as well on a WinForm.
private void myButton_Click(object sender, EventArgs e)
{
RadButton myButton = (RadButton)sender;
switch (myButton.Tag.ToString())
{
case "Indeterminant":
myButton.Tag = "On";
break;
case "On":
myButton.Tag = "Off";
break;
case "Off":
myButton.Tag = "Indeterminant";
break;
default:
break;
}
}

Related

Unity Dynamic UI number selection with plus and minus buttons

while programming a game in Unity, I had troubles with incrementing this new feature: a dynamic UI number selection with plus and minus buttons.
What I want precisely:
1. three buttons, one blank in the middle displays the number, two with plus and minus signs which, when clicked, increment or decrement number by 1. WORKS OK!
image of what I did
2. (this is where it gets tricky) When user presses for more than, say, .2s, then it increments the value of the central button pretty fast as long as the user is still pressing on the button. Would avoid player from pressing hundred times the button because it increments only by 1.
3. Eventually add an acceleration phase of the increase (at the start increases by 3/s for example and at the max by 20/s or something like that)
Some help on this would be really great, thanks for those who will take time answering :)
edit: found somebody who asked same question on another post -->https://stackoverflow.com/questions/22816917/faster-increments-with-longer-uibutton-hold-duration?rq=1 but I don't understand a single inch of code...(doesn't look like c#) ;( help!
Are you using the button's OnClick() Event? It only calls the function once even if the user is holding down the key.
If you are not sure how to configure it. Here is a tutorial, you can use.
https://vionixstudio.com/2022/05/21/making-a-simple-button-in-unity/
Also the middle button can be a text field.
edit: found the solution myself. The principal issue I encountered when trying to make the button was a way to know if the button was being pressed (a bool variable). I already knew when it was clicked and when it was released with the OnPointerUp and OnPointerDown methods in the event trigger component. I then found the Input.GetButton() funct, which returns true if the button passed in parameter (here the mouse's left click) is pressed.
Here's the code (I didn't make an acceleration phase 'cause I was bored but it can be done pretty easily once you've got the Input.GetButton statement):
public class PlusAndMinus : MonoBehaviour
{
[SerializeField] private GameManager gameManagerScript;
[SerializeField] private int amount;
private bool isPressedForLong=false;
[SerializeField] private float IncreasePerSecWhenPressingLonger;
public void PointerDown()
{
if (!gameManagerScript.isGameActive)
{
StartCoroutine(PointerDownCoroutine());
}
}
private IEnumerator PointerDownCoroutine()
{
yield return new WaitForSeconds(.1f);#.2f might work better
if (Input.GetMouseButton(0))
{
isPressedForLong = true;
}
}
public void PointerUp()
{
if (!gameManagerScript.isGameActive)
{
isPressedForLong = false;
gameManagerScript.UpdateNumberOfBalls("Expected", amount);
}
}
private void Update()
{
if (isPressedForLong)
{
gameManagerScript.UpdateNumberOfBalls("Expected", amount * IncreasePerSecWhenPressingLonger * Time.deltaTime);
}
}
}
The PointerDown event in the event trigger component calls the PointerDown function in the script (same for PointerUp).
The value of "amount" var is set to 1 for the plus button and -1 for the minus button.
The two if statements checking if game is not active are for my game's use but aren't necessary.
Finally, the gameManagerScript.UpdateNumberOfBalls("expected",amount); statements call a function that updates the text in the middle by the amount specified. Here's my code ("expected" argument is for my game's use):
#inside the function
else if (startOrEndOrExpected == "Expected")
{
if (!((numberOfBallsExpected +amount) < 0) & !((numberOfBallsExpected +amount) > numberOfBallsThisLevel))
{
if (Math.Round(numberOfBallsExpected + amount) != Math.Round(numberOfBallsExpected))
{
AudioManager.Play("PlusAndMinus");
}
numberOfBallsExpected += amount;
numberOfBallsExpectedText.text = Math.Round(numberOfBallsExpected).ToString();
}
}
0 and numberOfBallsThisLevel are the boundaries of the number displayed.
Second if statement avoids the button click sound to be played every frame when the user presses for long on the button (only plays when number increments or decrements by 1 or more).
Hope this helps!

Using CoRoutine Unity 3D Buttons

I'm currently making a quiz game that has three buttons, from an object pool, and I want them to turn green or red depending on whether or not they are the correct answer. This works perfectly.
When I add the coRoutine to change the button back to clear so the next question can be answered, the button almost never changes color after clicking and essentially nothing happens. Would really appreciate any help!! Thank you.
public void HandelClick()
{
var colors = GetComponent<Button> ().colors;
if( ! answerData.isCorrect)
{
colors.normalColor = Color.red;
GetComponent<Button>().colors = colors;
}
else
{
colors.normalColor = Color.green;
GetComponent<Button> ().colors = colors;
playerMovement.dodge();
}
StartCoroutine("Revert");
//gameController.AnswerButtonClicked(answerData.isCorrect);
}
IEnumerator Revert()
{
Debug.Log(" we are reverting " + Time.time);
yield return new WaitForSeconds(1.8f);
Debug.Log(" we are reverting again " + Time.time);
var colors = GetComponent<Button> ().colors;
colors.normalColor = Color.clear;
GetComponent<Button> ().colors = colors;
gameController.AnswerButtonClicked(answerData.isCorrect);
}
Changing the colors works as you said (you can see that in the Inspector of the Button)
The problem is that the Image component's color doesn't get updated automatically since the Button isn't receiving any pointer event like PointerDown, PointerExit etc => the new color is not applied to the Image (only in the cases where you do a new pointer event like enter, exit, up or down).
You could solve this by doing
GetComponent<Image>().color = colors.normalColor;
additional everywhere you change it.
Note: In general you should use GetComponent only once in Awake
private Button _button;
private Image _image;
private void Awake()
{
_button = GetComponent<Button>();
_image = GetComponent<Image>();
}
and than reuse the references _image and _button

OnDragListener not working properly

Hello everybody and thanks in advance.
I have a strange issue with one of my apps. This app is a MasterMind game which uses drag & drop, dragging coloured circles to holes.
This has been worked right with lots of devices, but recently I tried in a Galaxy S7 and Note 4 where the views(holes) have triggered the ACTION_DRAG_ENTERED outside the view.
Take a look at this screenshots to have a clearer idea...
< RIGHT BEHAVIOUR >
< WRONG BEHAVIOUR >
This is my listener...
class MiDragListener implements OnDragListener
{
#Override
public boolean onDrag(View v, DragEvent event)
{
int accion = event.getAction();
switch (accion)
{
case DragEvent.ACTION_DRAG_STARTED:
case DragEvent.ACTION_DRAG_EXITED:
v.setScaleX((float)1.0);
v.setScaleY((float)1.0);
break;
case DragEvent.ACTION_DRAG_ENTERED:
v.setScaleX((float)2.0);
v.setScaleY((float)2.0);
break;
case DragEvent.ACTION_DRAG_ENDED:
v.setScaleX((float)1.0);
v.setScaleY((float)1.0);
break;
case DragEvent.ACTION_DROP:
break;
default:
break;
}
return true;
}
} // end MiDragListener
although my code has not been changed.
Any help will be appreciated, thanks for your time and attention.

A way to check a BufferedImage repaint()?

I'm working in Eclipse and I want to know if I can make an if statement that checks to see if the BufferedImage has been painted/drawn onto the frame. For some reason, it's not painting the correct image because clickable regions are appearing on that picture when they are not supposed to.
For example, when I click the region to go from 4>5 everything is good. When I click from 5 to go to 4 I end up at 6 because the 'regions' from 4 are appearing in 5 (The image should always be painted before the clickable regions are shown) before it's even being painted. I want to restrict this to check if the image has been painted onto the frame first.
I really don't want to use anything else besides what I have right now (so no new classes being implemented to do this task), I really just want a simple yet effective way to resolve this. Here is what I'm talking about:
...
MouseAdapter mouseHandler = new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
repaint();
if(n==0)
{
if(e.getX()>=459 && e.getX()<491 && e.getY()>=111 && e.getY()<133
{
n = 4;
}
return;
}
if(n==5)
{
if(...)
{
n = 4;
}
return();
}
if(n==6)
{
if(...)
{
n = 5;
}
if(...)
{
n = 0;
}
if(...)
{
n = 6;
}
return();
}
}
...
I think you might need to give a little more information. The problem might lie in how you repaint, not whether it was painted.
If you are running another thread as your main program, you might instead want to send the mouse events synchronously to that so that the main thread can process the mouse click and then repaint.
Another solution might be to override the repaint method and paint the buffered images there, but you may have done that.
Also, a little off topic, I noticed that you used for loops to determine if the mouse was clicked in a specific area.
You could shorten the code:
for(int i=459; i<491; i++){
if(e.getX()==i){
for(int j=111; j<133; j++){
if(e.getY()==j){
//action taken
}
}
}
}
To:
if(e.getX()>=459 && e.getX()<491 && e.getY()>=111 && e.getY()<133{
//action taken
}
This would take up less space in your code and less time checking every pixel.
Back to your question.
I dont know of a function to tell if a buffered image has been painted. The ploblem that you are having though might of might not be in the code provided. Posting the rest of your code would be beneficial.
Okay I found the solution, I forgot to come back to this question and let you know. The problem was that the mouse was double clicking for some reason. You could almost say it was 'recursive'. I decided to move the mouseListener from inside the paintComponent to outside of it, and surely enough that fixed it.

Programatically Detect window maximization/Minimization??? Eclipse RCP

As the title shows, I want to add a listener to my rcp user interface in order to detect maximization and minimization. Actually, it not that my real purpose, but I think it is a way to solve my problem. I have a view with some shapes in the center, and I wonna keep the drawing exactly in the center even if the window is resized. To do so, I used the following listener :
public void createPartControl(final Composite parent) {
display = parent.getDisplay();
white= display.getSystemColor(SWT.COLOR_WHITE);
parent.setLayout(new FillLayout(SWT.VERTICAL));
final ScrolledComposite sc = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinHeight(100);
sc.setMinWidth(100);
sc.setSize(565, 305);
final Composite child = new Composite(sc,SWT.NONE);
child.setLayout(new FillLayout());
// Set child as the scrolled content of the ScrolledComposite
sc.setContent(child);
child.setBackground(white);
gc = new GC(child);
parent.addListener (SWT.Resize, new Listener () {
public void handleEvent (Event e) {
x = child.getBounds().width/2;
y = child.getBounds().height/2;
child.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
dessin(gc); // draw my shapes
}
});
}
everything goes well except when I maximize the window and then minimize it, in this case I loose the drawing (it is in the corner).
Any idea please? I'm I thinking in the right way?
The two events to detect minimization and un-minimization (not necessarily maximization) are Iconify and Deiconify which only occur on the Shell. See the javadocs for Shell.
Consider moving the resize event is seen for the parent, as the child need not necessarily be resized yet.
In order to keep something in the center of something else all you need is the SWT.Resize event, so this question is a classic case of the XY Problem. (Except that the OP in this case seems to already suspect that this may be an XY Problem.)
However, many people arrive at this question with a legitimate need to programmatically detect window minimized / maximized / restored events, for the following reason:
If you want to be able to save the bounds of your application window on exit, you cannot just save whatever is returned by Shell.getBounds(), because your application may be terminated while minimized or maximized or fullscreen, in which case its bounds should not be persisted. What should be persisted is the minimized/normal/maximized/fullscreen state of the shell, (I call it "posture",) and the bounds of the shell last time its posture was "normal". So, essentially, you need to keep track of when the posture is "normal", and for that you need to have a "posture changed" event.
The problem is that when SWT issues the "deiconified" event, it has not calculated the bounds of the shell yet, so the value that you get in that case is bogus.
So, here is the solution to that:
You are going to need a method which recalculates the posture as follows:
private void recalculatePosture()
{
Posture posture = swtShell.getFullScreen()? Posture.FULLSCREEN
: swtShell.getMinimized()? Posture.MINIMIZED
: swtShell.getMaximized()? Posture.MAXIMIZED
: Posture.NORMAL;
if( posture != previousPosture )
{
issue event...
previousPosture = posture;
}
}
In order to generate the "maximized", "restored (from maximized)" and "fullscreen" events you can use Shell.addListener() to listen for the SWT.Move and SWT.Resize event, and invoke recalculatePosture() when they occur.
In order to generate the "minimized" event you can use the shellIconified() method of the ShellListener as #the.duckman said, and again, invoke recalculatePosture().
In order to generate the "restored (from minimized)" event, you need to do the following in your ShellListener:
#Override
protected void onShellDeiconified( ShellEvent e )
{
display.asyncExec( () -> recalculatePosture() );
}
This will cause the recalculation of posture a short time after the 'deiconified' event, at which point SWT will have gotten around to properly calculating the bounds of the shell.