How to find the clicked button in the action method - button

When I have a dialog and multiple buttons have the same click-callback (action method) I mostly want to know which button has been pressed. How do I do that?
Example:
class ButtonDialog : UIFrame{
void button_pressed(object self){
// how do I get this button
TagGroup pressed_button = ?;
result("The button " + pressed_button + " is pressed.\n");
}
object init(object self){
TagGroup dlg, dlg_items, button1, button2;
dlg = DLGCreateDialog("Press a button", dlg_items);
button1 = DLGCreatePushButton("Button 1", "button_pressed");
button1.DLGIdentifier("button1");
dlg_items.DLGAddElement(button1);
button2 = DLGCreatePushButton("Button 2", "button_pressed");
button2.DLGIdentifier("button2");
dlg_items.DLGAddElement(button2);
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();
In my current program I have multiple rows created from a TagGroup. Each row has multiple buttons doing the same thing but for their specific row. Therefore I need to know which button it is to get the row to modify. Also the length of the TagGroup and therefore the row count is not fixed. So I cannot create button1_pressed, button2_pressed, ... functions except with doing some weird stuff with code evaluation on the fly which I want to avoid if possible.

The fact that you cannot pass an argument in the simple call-back of a push-button is a bit of a bummer. The easiest solution (albeit not elegant) is to use simple-one-line-callback methods which are unique but themselves call a generalized method as in the code below.
Of course mile7 stated that the number of buttons isn't fixed at compile time, which is an issue here. But unless the (potential) number of buttons is legion, this approach is still the easiest and cleanest, and as each "hard coded" call-back is only one line with a very systemic change, it should be fairly trivial to use Notepad++ or similar to provide an extensive enough set of such calls. (It doesn't hurt if some of them are actually never used.)
class ButtonDialog : UIFrame{
void button_pressed(object self, string buttonID){
// how do I get this button
TagGroup pressed_button = self.LookUpElement(buttonID);
if ( pressed_button.TagGroupIsValid() )
result("The button " + buttonID + " is pressed.\n");
else
result("The button " + buttonID + " was not found!\n");
}
// Need to be done for each button
void button_pressed_0(object self) { self.button_pressed("button0"); }
void button_pressed_1(object self) { self.button_pressed("button1"); }
object init(object self){
TagGroup dlg, dlg_items
dlg = DLGCreateDialog("Press a button", dlg_items);
number nButtons = 2
for( number n=0; n<nButtons; n++ ){
TagGroup button = DLGCreatePushButton("Button " + n , "button_pressed_" + n);
button.DLGIdentifier("button" + n);
dlg_items.DLGAddElement(button);
}
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();

So I kind of found an answer which I can live with, but I'm still hoping for better results.
My current idea is to use DualStateBevelButtons. If a button gets clicked, the state changes and the callback is executed. Then all buttons are checked if they have a changed state. If so, this is the clicked button and the state is reset.
The very very big downside of this solution is, that there are only buttons with images allowed, no text is possible. So this is not really the general solution to work with.
rgbimage button_img = RGBImage("button-image", 4, 16, 16);
button_img = max(0, 255 - iradius / 8 * 255);
class ButtonDialog : UIFrame{
TagGroup buttons;
void button_pressed(object self){
for(number i = 0; i < buttons.TagGroupCountTags(); i++){
TagGroup button;
if(buttons.TagGroupGetIndexedTagAsTagGroup(i, button)){
if(button.DLGGetValue() == 1){
// this button is toggled so it is clicked
string identifier;
button.DLGGetIdentifier(identifier);
result("Button " + i + " (" + identifier + ") is clicked.\n");
// reset button state
button.DLGBevelButtonOn(0);
// do not continue searching, found pressed button already
break;
}
}
}
}
object init(object self){
TagGroup dlg, dlg_items, button1, button2;
dlg = DLGCreateDialog("Press a button", dlg_items);
buttons = NewTagList();
button1 = DLGCreateDualStateBevelButton("button1", button_img, button_img, "button_pressed");
buttons.TagGroupInsertTagAsTagGroup(infinity(), button1);
dlg_items.DLGAddElement(button1);
button2 = DLGCreateDualStateBevelButton("button2", button_img, button_img, "button_pressed");
buttons.TagGroupInsertTagAsTagGroup(infinity(), button2);
dlg_items.DLGAddElement(button2);
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();

Related

Very simple if else check in Google App Maker

This is likely embarrassingly easy but I'm new and I've been beating my head against the wall on this for a while now. What I am attempting to do is basically a modified version of the "Hello App Maker!" If else test.
The necessary info I have the following widgets attached to the appropriate data sources:
Dropdown widget called source_name (string - list)
Label widget I've called name (string)
Text Box widget called qty_duration (number)
Label widget I've called hours (number)
I have a dropdown widget called source_name with 5 options. On selection I have the value appear in a label widget I've called name. If the option selected from the drop down widget is ever LABOUR I am trying to then have the value of a Text Box widget called qty_duration appear in a label widget I've called hours
On the source_name dropdown event - onValueChange I have the following code:
// Define variables for the input and output widgets
var nameWidget = app.pages.Apex_job_details.descendants.name;
var outputWidget = app.pages.Apex_job_details.descendants.hours;
var techhours = app.pages.Apex_job_details.descendants.qty_duration;
var nothing = 0;
// If a name is LABOUR, add the qty to the output widget Else output 0.
if (nameWidget == 'LABOUR') {
outputWidget.text = techhours;
} else {
outputWidget = nothing;
}
It's not giving me any errors, but it's also not outputting to the hours label. If I edit the code as follows just to muck with it:
// Define variables for the input and output widgets
var nameWidget = app.pages.Apex_job_details.descendants.name;
var outputWidget = app.pages.Apex_job_details.descendants.hours;
var techhours = app.pages.Apex_job_details.descendants.qty_duration;
var nothing = 0;
// If a name is LABOUR, add the qty to the output widget Else output 0.
if (nameWidget == 'LABOUR') {
outputWidget.text = techhours;
} else {
outputWidget.text = nothing;
}
I'm not sure what I'm doing wrong.
Assuming all labels and input widgets are inside a table row you will want to adjust your code as follows:
var tablerow = widget.parent;
var nameWidget = tablerow.descendants.name.text;
var outputWidget = tablerow.descendants.hours;
var techhours = tablerow.descendants.qty_duration.value;
if(nameWidget === 'LABOUR') {
outputWidget.text = techhours;
} else {
outputWidget.text = null;
}
By using widget.parent in the onValueChange event of the dropdown you will automatically reference the table row and then by using descendants you are referencing only the descendants of that table row. This will bridge the error by using an absolute reference when using table rows. If it still doesn't work let me know.

Deleting a dinamically generated UI in QT?

I'm doign a file transfer manager on Dialog the needs to dynamically generate a couple of UI elements. Here is the function that generates it:
void TransferData::createGraphicalUI(QDialog *parent, qint32 td_id){
status = new QLabel(parent);
filename = new QLabel(parent);
contact_label = new QLabel(parent);
accept = new IDPushButton(parent,td_id);
reject = new IDPushButton(parent,td_id);
cancel = new IDPushButton(parent,td_id);
progress = new QProgressBar(parent);
statlayout = new QHBoxLayout();
frameLayout = new QVBoxLayout();
frame = new QFrame(parent);
// Stylying the frame
frame->setStyleSheet("background-color: rgb(255, 255, 255);");
// Setting the messages.
QString htmlHeader = "<html><head/><body><p><span style='font-weight:792; color:#0000ff;'>";
QString htmlEnder = "</span></p></body></html>";
QString contactMsg = "Transfer ";
QString filenameMsg = "File name: </span><span>" + getFileToBeSent();
QString statusMsg = "Status: </span><span>";
cancel->setText("Cancel");
cancel->setIcon(QIcon(":/Icons/icons/cancel.png"));
cancel->setVisible(false);
if (getIsATransfer()){
// This is a transfer TO, the file will be uploaded
contactMsg = contactMsg + "to: </span><span> " + getConctacName();
statusMsg = statusMsg + "Waiting for file to be accepted.";
statlayout->addWidget(status);
statlayout->addWidget(cancel);
accept->setVisible(false);
reject->setVisible(false);
}
else{
// This is a transfer FROM, the file will be downlaoded
contactMsg = contactMsg + "from: </span><span> " + getConctacName();
statusMsg = statusMsg + "Transfer must be accepted before it begins.";
accept->setText("Accept");
accept->setIcon(QIcon(":/Icons/icons/ok.png"));
reject->setText("Reject");
reject->setIcon(QIcon(":/Icons/icons/cancel.png"));
statlayout->addWidget(status);
statlayout->addWidget(accept);
statlayout->addWidget(reject);
statlayout->addWidget(cancel);
}
status->setText(htmlHeader + statusMsg + htmlEnder);
filename->setText(htmlHeader + filenameMsg + htmlEnder);
contact_label->setText(htmlHeader + contactMsg + htmlEnder);
// Resettign the progress bar
progress->setValue(0);
// Putting it all together.
frameLayout->addWidget(contact_label);
frameLayout->addWidget(filename);
frameLayout->addLayout(statlayout);
frameLayout->addWidget(progress);
frame->setLayout(frameLayout);
}
This is called from a function that has a list of TransferData objects:
qint32 TransferManager::addTransfer(TransferData td){
// Getting the ID for this tranfer
qint32 transferID = transfers.size();
td.createGraphicalUI(this,transferID);
// Adding it to the UI
ui->globalTMLayout->addWidget(td.getFrame());
connect(td.getAcceptButton(),SIGNAL(wasClicked(qint32)),this,SLOT(onTransferAccepted(qint32)));
connect(td.getRejectButton(),SIGNAL(wasClicked(qint32)),this,SLOT(onTransferRejected(qint32)));
connect(td.getCancelButton(),SIGNAL(wasClicked(qint32)),this,SLOT(onTransferCanceled(qint32)));
// Adding the TD
transfers << td;
// If a transfer is added this needs to be shown
this->show();
return transferID;
}
Once the transfer is done I need to delete all the elements of the created UI. I do it like this:
void TransferManager::removeTransferData(qint32 which){
if (which < transfers.size()){
// Deleting the UI
transfers[which].removeGraphicalUI();
// Removing the frame
QFrame *frame = transfers.at(which).getFrame();
ui->globalTMLayout->removeWidget(frame);
// Removing the data itself
transfers.removeAt(which);
}
}
Where removeGraphicalUI is this function:
void TransferData::removeGraphicalUI(){
frameLayout->removeWidget(progress);
frameLayout->removeWidget(filename);
frameLayout->removeWidget(contact_label);
statlayout->removeWidget(cancel);
statlayout->removeWidget(status);
if (!getIsATransfer()){
statlayout->removeWidget(accept);
statlayout->removeWidget(reject);
}
}
What happens is that the frame is removed but everythign that was inside the frame remains. I've checked with a printed message an the code IS enering the removeUI function.
So why does this not work and what Is the proper way to delete dinamically generated UI?
Thanks!
Ok, so I haven't found the answer to my question but I did find the way to do this:
Basically the documentation says that when a QWidget descendant object is deleted, all their childs are deleted.
So what I did is basically used the QFrame as the parent for everything BUT the the layouts.
Then when I wanted to delete said frame I would simply invoke:
frame->~QFrame()
In the removeGraphicalUI() function and NOTHING more. Also I've commented this:
void TransferManager::removeTransferData(qint32 which){
if (which < transfers.size()){
// Deleting the UI
transfers[which].removeGraphicalUI();
// Removing the frame
// QFrame *frame = transfers.at(which).getFrame();
// ui->globalTMLayout->removeWidget(frame);
// Removing the data itself
transfers.removeAt(which);
}
}
As removing the frame from the GUI was no longer necessary. I hope this helps someone.

Add itemEditorValidatorFunction with Pop up window confirmation to Flexicious Grid

I am trying to have my Flexicious DataGrid ask for confirmation of a change when I click in a cell to edit a value and enter a new value which deviates from the original by a certain percentage. I cannot see an easy way to do this. Initially, I tried to write a itemEditorValidatorFunction, which returns a boolean. This works perfectly for a hard coded return value, but if I try to take the return value from the CloseEvent of an Alert, that value is ignored:
protected function validateGcCap(editor:UIComponent):Boolean{
var warningBPDiffVal:Number = Number(5);
var warningPerCentDiffVal:Number = Number(warningBPDiffVal / 1000);
var allowChange:Boolean = true;
var origGcCapVal:Number = Number(managerGrid.getCurrentEditingCell().text);
var newGcCapVal:Number = Number((editor as TextInput).text);
var diffVal:Number = Number(newGcCapVal - origGcCapVal);
if (origGcCapVal > newGcCapVal) {
diffVal = origGcCapVal - newGcCapVal;
}
if (diffVal > warningPerCentDiffVal) {
//Alert.show("you changed the gccap from " + origGcCapVal + " to " + newGcCapVal + " by " + diffVal);
function alertCloseHandler(event:CloseEvent):void{
if (event.detail == Alert.CANCEL) {
allowChange = false;
}
};
var alert:Alert = Alert.show("Are you sure that you want to update gcCap% by more than " + warningBPDiffVal + "bps?",
"Please Confirm", (Alert.OK | Alert.CANCEL),
this, alertCloseHandler);
}
return allowChange;
}
I also tried to write a itemEditor for the grids:FlexDataGridColumn, where I extended com.flexicious.controls.TextInput, but I could not work out which method to override. I wanted to override the method and only make the call to super if the Alert was clicked OK, but I could not see which method I should override. I tried override protected function onTextInput(textEvent:TextEvent):void, but this did nothing.
I would be grateful for any insight into this problem.
Not sure why someone decided to downvote your question, it seems quite valid. From looking at this, the best way for you would be to "undo" the edit when the user selects no on the box. If you have enableTrackChanges on, all you have to do is to remove that change from the dgGrid.changes collection and call dgGrid.refreshCells(). If you dont have enableTrackChanges, all you need to do is to update the dataProvider row with the old value, call dgGrid.refreshCells() and you should be set.
This is what works:
private function validateGcCap(editor:UIComponent):Boolean{
var warningBPDiffVal:Number = Number(5);
var cell:IFlexDataGridCell = managerGrid.getCurrentEditingCell();
var warningPerCentDiffVal:Number = Number(warningBPDiffVal / 1000);
var origGcCapVal:Number = Number(cell.text);
var newGcCapVal:Number = Number((editor as TextInput).text);
var diffVal:Number = Number(newGcCapVal - origGcCapVal);
if (origGcCapVal > newGcCapVal){
diffVal = origGcCapVal - newGcCapVal;
}
if (diffVal > warningPerCentDiffVal){
function alertCloseHandler(event:CloseEvent):void{
if (event.detail == Alert.CANCEL) {
IAParamsVO(cell.rowInfo.data).gcCapWrapper = origGcCapVal;
managerGrid.refreshCells();
}
}
Alert.show("Are you sure that you want to update gcCap% by more than "
+ warningBPDiffVal + "bps?", "Please Confirm", (Alert.OK | Alert.CANCEL),
this, alertCloseHandler);
}
return true;
}

Depending source for drop down list

I have one drop down list in my pages that its source comes of below code. Now I like to put 1 text box adjusted on my drop down list and when I type on that, source of drop down list (DocumentNo) depend on what I type in the text box and when text box is null drop downs list shows all the (DocumentNo) , please help how I have to change my code,
protected void ddlProjectDocument_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var query = from p in _DataContext.tblDocuments
orderby p.DocumentNo
select p;
int maxs = 0;
foreach (tblDocument v in query)
{
if (v.DocumentNo.Length > maxs)
maxs = v.DocumentNo.Length;
}
foreach (tblDocument vv in query)
{
string doctitle = vv.DocumentNo;
for (int i = vv.DocumentNo.Length; i < maxs; i++)
{
doctitle += " ";
}
doctitle += " | ";
doctitle += vv.TITLE;
// Use HtmlDecode to correctly show the spaces
doctitle = HttpUtility.HtmlDecode(doctitle);
ddlProjectDocument.Items.Add(new ListItem(doctitle, vv.DocId.ToString()));
}
}
First, I would highly recommend storing the result of that query at the beginning of the method into something like a session variable so that you don't have to continually query the database every time you hit this page.
Second, you should use the OnTextChanged event in ASP.NET to solve this problem. Put in the OnTextChanged attribute to point to a method in your code behind that will grab the query result values (now found in your session variable) and will reset what is contained in ddlProjectDocument.Items to anything that matched what was being written by using String.StartsWith():
var newListOfThings = queryResults.Where(q => q.DocumentNo.StartsWith(MyTextBox.Value));
At this point all you need to do is do that same loop that you did at the end of the method above to introduce the correct formatting.

Move cursor inside textarea to end

I have a text area control on a form that is supposed to accept 5 digit US zip codes. I have assigned the control a keyUp event that checks the number of characters entered until it reaches 5 then forces a new line.
public function forceNewLine(event:KeyboardEvent):void
{
var maxLineChars:int = 5;
var currentLine:int = 1;
var numChars:int;
numChars = (txtList.text.length);
currentLine = Math.round(txtList.text.length / 6);
if (numChars == (maxLineChars * currentLine))
{
txtList.text = txtList.text + "\n";
txtList.setCursorPosition()
//This is not a function I have defined but I think I need too..
}
}
<s:TextArea id="txtList" keyUp="forceNewLine(event)"/>
It works fine except that when the new line is inserted, the cursor moves to the beginning of the textarea. I want it to go to the end.
Try using the selectRange function of the spark textArea.
txtList.selectRange(txtList.text.length, txtList.text.length)

Resources