Detecting which UI button was pressed within canvas? - button

I have like 10 buttons on my UI and I gotta check which one was touched. I was using the following logic and it was working fine, but now I am getting this error for some reason:
NullReferenceException: Object reference not set to an instance of an object
DetectButton.Start () (at Assets/Scripts/DetectButton.cs:14)
Any ideas what could be going on? Here is my code (attached to the canvas), and I am using Unity version 5.1.0f3. If you need any other info I will gladly provide, thanks in advance
void Start()
{
this.GetComponent<Button>().onClick.AddListener(() =>
{
if (this.name == "btnJogadores2")
{
print ("2 jogadores");
jogadores = 2;
}
//QuantidadeJogadores(this.name);
//QuantidadePartidas(this.name);
});
}

You don't have to all this the way you are doing.
An Easier and good practice would be to create 10 separate GameObjects for each button inside your canvas. and then create a single script with 10 separate functions for all those buttons in it. Attach that script to you canvas. and then on the button GameObject select the script on the desired function. Sample below
void Start() { }
void Update() { }
public void button1()
{
Debug.Log("Button3");
}
public void button2()
{
Debug.Log("Button1");
}
public void button3()
{
Debug.Log("Button3");
}
NOTE: button1, button2 and button3 are the functions for 3 separate buttons
Then inside your unity Inspector:
Select your script with you button functions.
Assign you desired method to you button.
After this run your scene and your button will call the assigned methods properly.

Code is not tested, but it should get you started to get all the Buttons.
void Start() {
var buttons = this.GetComponents<Button> ();
foreach(var button in buttons) {
button.onClick.AddListener(() = > {
if (this.name == "btnJogadores2") {
print("2 jogadores");
jogadores = 2;
}
//QuantidadeJogadores(this.name);
//QuantidadePartidas(this.name);
});
}
}
Actually it will be hard to distinguish between the buttons.
The more practical aproach would be to make 10 GameObjects (Child of the Canvas) and attach your Script to everyone of them.

Related

Persistent header fragment (disable animation) in Android TV (leanback)

Anyone knows how to achieve the question in the title? The objective is to avoid the animation that results in the Headers bar disappearing as the Leanback app zooms in on the Row Item once a Header has been clicked.
setHeadersState of BrowseSupportFragment doesn't help. Perhaps something to do with hijacking startHeadersTransitionInternal during OnHeaderClickedListener? If so, any idea how to correctly implement it?
So the problem with this one is that the transition is handled by the method startHeadersTransitionInternal which is package private. Because of this, you can't override it in most situations. However, since it's only package private and not private private, there's a little hack around this that you can do.
First, make a package in your app with the same package name as BrowseSupportFragment. Then make a class in that package that extends BrowseSupportFragment and override the offending method with no implementation. That'd look something like this:
package android.support.v17.leanback.app; // Different for AndroidX
public class HackyBrowseSupportFragment extends BrowseSupportFragment {
#Override
void startHeadersTransitionInternal(boolean withHeaders) {
// Do nothing. This avoids the transition.
}
}
Then, instead of extending BrowseSupportFragment, you'd extend HackyBrowseSupportFragment.
One thing to note that I found with this is that the back button will no longer refocus the headers from one of the rows, so you'll have to do that manually. Other than that, seems to work just fine.
Following #MichaelCeley 's response and based on the original startHeadersTransitionInternal method from BrowseSupportFragment, this implementation that keeps the backstack and listeners works, too.
#Override
void startHeadersTransitionInternal(final boolean withHeaders) {
if (getFragmentManager().isDestroyed()) {
return;
}
if (!isHeadersDataReady()) {
return;
}
new Runnable() {
#Override
public void run() {
if (mBrowseTransitionListener != null) {
mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
}
if (mHeadersBackStackEnabled) {
if (!withHeaders) {
getFragmentManager().beginTransaction()
.addToBackStack(mWithHeadersBackStackName).commit();
} else {
int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
if (index >= 0) {
FragmentManager.BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
getFragmentManager().popBackStackImmediate(entry.getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
}
}
}.run();
}

Confused on ActionListeners

Hello fellow coders of the night,
I am stuck with a moral dilemma (well not moral, but mostly i don't know what to do).
Suppose I have one button that can do several actions, depending on the menu item which is chosen.
Basically, I've imagined this
private void menuButtonActionPerformed(ActionEvent b)
ActionEvent a
if(a.getSource()==menuItem)
if(b.getSource()==button)
do this and that
Is this the correct way to do this? because if it is I'd have to add ActionListeners on the menuItem but I get stuck with some stupid error code somewhere!
Thanks in advance for helping me!
Post Scriptum : #David, I've tried this, however the initial condition isn't verified.
private void buttonValidateActionPerformed(java.awt.event.ActionEvent evt)
ActionListener l = (ActionEvent e) -> {
if(e.getSource()==menuItemAdd)
{
System.out.println("eureka!");
buttonSearch.setEnabled(false);
if (evt.getSource()==buttonValidate)
{
DataTransac dt = new DataTransac();
dt.addCoders("...");
}
}
if(e.getSource()==itemDelete)
{
DataTransac dt = new DataTransac();
dt.deleteCoders("...");
}
};
menuItemAdd.addActionListener(l);
itemDelete.addActionListener(l);
That won't work; your listener will get a different invocation for each time the listener is used -- so the event source will be either a button or a menu item for a single invocation.
You'll need to respond to the menu item with one ActionListener that stores state, and then separately handle the button action. You could do this with one listener, but I wouldn't; I'd do this:
private MenuItem selected;
private class MenuItemListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
// if you really want to have one listener for multiple menu items,
// continue with the .getSource() strategy above, but store some
// state outside the listener
selected = (MenuItem)event.getSource();
// you could alternatively have a different listener for each item
// that manipulates some state
}
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
// take conditional action based on selected menu item, as you describe
// in the question
}
}
void setup() {
JMenuItem first = /* ... */;
JMenuItem second = /* ... */;
MenuItemListener listener = new MenuItemListener();
first.addActionListener(listener);
second.addActionListener(listener);
JButton button = /* ... */;
button.addActionListener(buttonListener);
}
Generally speaking this is the preferred approach -- use a different listener for each semantic action, rather than one that introspects the source. Your code will be cleaner, simpler, and easier to understand.
For the same reasons, some people prefer to use anonymous classes for Java event listeners. Here's a Gist that shows several syntaxes: https://gist.github.com/sfcgeorge/83027af0338c7c34adf8. I personally prefer, if you are on Java 8 or higher:
button.addActionListener( event -> {
// handle the button event
} );

Why does my label disappear on button click?

I am brand new to Qt development and am trying to make a simple "Hello, World" with a toggle-button. I have something like this:
with the corresponding code:
void MainWindow::on_pushButton_toggled(bool checked)
{
if(checked) {
ui->label->setText("Hello, World!");
} else {
ui->label->setText("");
}
}
My goal is to change the label's text either from blank to "Hello, World!" or vice versa on a button click.
Currently the label only stays blank. Earlier the default text was "TextLabel", and on a button-click, it would change from "TextLabel" to blank, which is almost correct.
I've tried different options like on_pushButton_clicked, but to no avail.
I know the solution is a simple one -- can anyone point me in a good direction?
Why don't you do it like this?
void MainWindow::on_pushButton_toggled(bool checked)
{
ui->label->setText(ui->label->text().isEmpty() ? "Hello, World!" : "");
}
You need to declare your callback method as below :
class MainWindow : public QMainWindow
{
Q_OBJECT
bool checked;
QPushButton *my_button;
private slots:
void handleButton();
};
Then in your Constructor you need to connect Signal and Slot as below :
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
checked = 0;
connect(my_button, SIGNAL (released()), this, SLOT (on_pushButton_toggled()));
}
Your call back method will be like this. You can toggle your flag in this method as every time you click this SLOT will be called.
void MainWindow::on_pushButton_toggled()
{
checked = ~checked;
if(checked) {
ui->label->setText("Hello, World!");
} else {
ui->label->setText("");
}
}
I hope this will work out for you.
QPushButton is not checkable by default; you need to call QAbstractButton::setCheckable(true); before you can really use the QAbstractButton::toggled signal in any meaningful way. What happens in your code is that your slot is being called with the value false passed every single time because the button simply isn't checkable.

TranslateTransition in JavaFX does nothing

I'm trying to use a TranslateTransition object in JavaFX to move an onscreen object in a LOGO program I am building. I have an onscreen TurtleDisplay object, which extends ImageView, and this is what I'm trying to move. The code to move it is here:
public void drawTurtle(TurtleData currentData) {
TurtleImage inList = getTurtleImage(currentData);
if (inList==null) {
TurtleImage temp = new TurtleImage(currentData.getX(),
currentData.getY(), currentData.getHeading(), turtleImage);
myTurtlesGroup.getChildren().add(temp);
myTurtlesList.add(temp);
}
else {
TranslateTransition tt = new TranslateTransition(Duration.seconds(3),inList);
tt.setFromX(inList.getX());
tt.setFromY(inList.getY());
tt.setToX(inList.getX()+currentData.getX());
tt.setToY(inList.getY()+currentData.getY());
tt.setCycleCount(Timeline.INDEFINITE);
tt.play();
}
}
This code, which is part of the front end, is called from the back end via a Listener on an ObservableList. The backend contains this ObservableList of TurtleData objects that contain the information necessary to move a turtle on screen -- which turtle to move, the coordinate to move to, and the rotation of the turtle. The code to call this is here:
ObservableList<TurtleData> myTurtles = FXCollections
.observableArrayList();
myTurtles.addListener(new ListChangeListener<TurtleData>() {
#Override
public void onChanged(Change<? extends TurtleData> c) {
myDisplay.getSelectedWorkspace().getTV().clearTurtles();
while (c.next()) {
for (TurtleData addItem : c.getAddedSubList()) {
myDisplay.getSelectedWorkspace().getTV().drawTurtle(addItem);
}
}
}
});
I have stepped through with a debugger and ensured that this code is called -- specifically, the tt.play() line is run. Nothing moves on screen. Does anyone have any idea what is wrong? Do I need to setup an Animation Timeline? Thank you for any help!

Alternative to QButtonGroup that allows no selection?

I'm writing a qt-based c++ application. I have a number of buttons that I want to be mutually exclusive - only one can be toggled at a time. I generally use a QButtonGroup for this - it provides a nice logical way to manage sets of buttons. When one gets pressed, the previously-pressed one gets unpressed, which is exactly the behavior I want.
This time, however, I'd like to allow for the group to be entirely unchecked. Unfortunately this seems to be disallowed by QButtonGroup:
exclusive : bool
This property holds whether the button group is exclusive.
If this property is true then only one button in the group can be
checked at any given time. The user can click on any button to check
it, and that button will replace the existing one as the checked
button in the group.
In an exclusive group, the user cannot uncheck the currently checked
button by clicking on it; instead, another button in the group must be
clicked to set the new checked button for that group.
There are a number of ways to work around this, of course. I'm wondering if there's a pre-made alternative to QButtonGroup that allows this behavior, so that 1) I'm not reinventing the wheel and 2) I can stay within idiomatic qt to make project management easier in the future.
Any suggestions?
In Qt5, I use a similar solution as Laurent Michel's, but using the release event instead of the press event:
// Allow to uncheck button in exclusive group
void CustomButton::mouseReleaseEvent(QMouseEvent* a_Event) {
if(group()->checkedId()==group()->id(this)) {
if(isDown()) group()->setExclusive(false);
}
QToolButton::mouseReleaseEvent(a_Event);
group()->setExclusive(true);
}
For the sake of completeness, I would like to publish here one possible solution to the problem, as I just solved it in my case. Just beware that the following code is valid for Qt3. It may as well work for Qt4 and Qt5, because it doesn't use a lot of stuff.
So, I assume that I have a widget CustomWidget somewhere that contains buttons (of type CustomButton) and that one and only one button can be switched on. If one clicks another button in the widget, then the currently switched on button is switched off and the newly clicked button is switched on.
The CustomButtons contained in the CustomWidget are all contained in a QButtonGroup in the following way:
QButtonGroup* m_ButtonGroup = new QButtonGroup(this);
m_ButtonGroup->hide();
m_ButtonGroup->insert(Btn1);
m_ButtonGroup->insert(Btn2);
m_ButtonGroup->insert(Btn3);
m_ButtonGroup->setExclusive(true);
Here, Btn1, Btn2, and Btn3 are of type CustomButton
class CustomButton : public QToolButton
{
Q_OBJECT
public:
CustomButton (QWidget* apo_parent = 0, const char* as_name = 0);
virtual ~CustomButton ();
protected:
virtual void mousePressEvent(QMouseEvent* a_Event);
};
The method you want to implement specially is mousePressEvent. If its body is implemented in the following way:
void CustomButton ::mousePressEvent(QMouseEvent* a_Event)
{
if(group() && isToggleButton())
{
CustomButton* selectedButton(dynamic_cast<CustomButton*>(group()->selected()));
if(selectedButton)
{
if(selectedButton->name() == name())
{
group()->setExclusive(false);
toggle();
group()->setExclusive(true);
return;
}
}
}
QToolButton::mousePressEvent(a_Event);
}
then the widget behaves as you want.
Another similar solution as the previous answers, but using nextCheckState() which appears to be the more natural extension point to me:
void MyButton::setSemiExclusive(bool value)
{
mSemiExclusive = value;
}
void MyButton::nextCheckState()
{
if (mSemiExclusive)
{
if (auto g = group())
{
auto old = g->exclusive();
if (g->checkedButton() != this)
g->setExclusive(true);
QAbstractButton::nextCheckState();
g->setExclusive(old);
return;
}
}
QAbstractButton::nextCheckState();
}
This depends on the associated QButtonGroup having set exclusive to false.
If you don't want to extend the button class, you can also accomplish this by using signals (Qt5, Python):
from PySide import QtGui
class View(QtGui.QWidget):
def __init__(self):
self.buttonGroup = QtGui.QButtonGroup(self)
for button in buttons:
self.buttonGroup.addButton(button)
button.pressed.connect(buttonPressed)
button.released.connect(buttonReleased)
def buttonPressed(self):
button = self.sender()
checkedButton = self.buttonGroup.checkedButton()
if checkedButton != None and checkedButton.objectName() == button.objectName():
self.buttonGroup.setExclusive(False)
def buttonReleased(self):
button = self.sender()
if self.buttonGroup.exclusive() == False:
button.setChecked(False)
self.buttonGroup.setExclusive(True)
def manualDeselection:
self.buttonGroup.setExclusive(False)
self.buttonGroup.checkedButton().setChecked(False)
self.buttonGroup.setExclusive(True)
My solution is to derive the QButtonGroup, set it to non exclusive internaly and manage the states by yourself
class myQButtonGroup : public QButtonGroup
{
Q_OBJECT
public:
explicit myQButtonGroup(QObject *parent = Q_NULLPTR) : QButtonGroup(parent) {
_bExclusive = true;
QButtonGroup::setExclusive(false);
connect(this, SIGNAL(buttonClicked(QAbstractButton *)), SLOT(buttonClicked(QAbstractButton *)));
}
void setExclusive(bool bExclusive) { _bExclusive = bExclusive; }
bool exclusive() const { return _bExclusive; }
protected slots:
void buttonClicked(QAbstractButton *button) {
if (_bExclusive) {
// just uncheck all other buttons regardless of the state of the clicked button
QList<QAbstractButton *> buttonlist = buttons();
for (auto iBtn = buttonlist.begin(); iBtn != buttonlist.end(); ++iBtn) {
QAbstractButton *pBtn = *iBtn;
if (pBtn && pBtn != button && pBtn->isCheckable()) pBtn->setChecked(false);
}
}
}
protected:
bool _bExclusive;
};

Resources