I've created an ALV tree view with use of the class CL_SALV_TREE.
Everything works fine but I'd like to grap the event when a node is expanded, for filling in a function that automatically resizes the tree columns.
My problem is, that the expanding event is the private method HANDLE_EXPAND_NC of class CL_GUI_ALV_TREE and I actually don't know how to capture this event. I'm open for any ideas and thanks for your time.
As far as I know, you can only be notified if a folder is expanded that does not yet contain children (the _NC part of the method/event name signifies that). This is intended for lazy loading of the tree. The tree displays in the SAP menu or the IMG are a good example for that - you can actually see parts of the tree being loaded when you expand the top-level nodes.
If that is sufficient for you, use the event EXPAND_EMPTY_FOLDER of the interface IF_SALV_EVENTS_TREE, implemented by CL_SALV_EVENTS_TREE. There doesn't seem to be a good demo program for this though.
Here is a minimal reproducible example which shows that the event EXPAND_EMPTY_FOLDER is triggered when you expand a node which has no children initially, a child node is added during that event:
CLASS lcl_app DEFINITION.
PUBLIC SECTION.
METHODS pbo
RAISING
cx_salv_error.
PRIVATE SECTION.
DATA: salv TYPE REF TO cl_salv_tree,
scarrs TYPE STANDARD TABLE OF scarr.
METHODS on_expand_empty_folder
FOR EVENT expand_empty_folder
OF cl_salv_events_tree
IMPORTING node_key.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD pbo.
IF salv IS NOT BOUND.
cl_salv_tree=>factory( EXPORTING r_container = cl_gui_container=>screen0
IMPORTING r_salv_tree = salv
CHANGING t_table = scarrs ).
DATA(lo_settings) = salv->get_tree_settings( ).
lo_settings->set_hierarchy_size( 30 ).
DATA(event) = salv->get_event( ).
salv->get_functions( )->add_function( name = 'NEW' text = 'NEW' tooltip = '' position = 1 ).
SET HANDLER on_expand_empty_folder FOR event.
SELECT * FROM scarr INTO TABLE #DATA(local_scarrs).
LOOP AT local_scarrs REFERENCE INTO DATA(scarr).
salv->get_nodes( )->add_node(
related_node = space " (root node)
relationship = cl_gui_column_tree=>relat_last_child
text = |{ scarr->carrid } - { scarr->carrname }|
data_row = scarr->*
folder = abap_true
expander = abap_true ).
ENDLOOP.
salv->display( ).
ENDIF.
LOOP AT SCREEN.
screen-active = '0'.
MODIFY SCREEN.
ENDLOOP.
ENDMETHOD.
METHOD on_expand_empty_folder.
TRY.
DATA(scarr) = CAST scarr( salv->get_nodes( )->get_node( node_key )->get_data_row( ) )->*.
salv->get_nodes( )->add_node(
related_node = node_key
relationship = cl_gui_column_tree=>relat_last_child
text = |Node added at time of expand below { scarr-carrid }| ).
CATCH cx_root INTO DATA(lx).
MESSAGE lx TYPE 'I' DISPLAY LIKE 'E'.
LEAVE PROGRAM.
ENDTRY.
ENDMETHOD.
ENDCLASS.
PARAMETERS dummy.
LOAD-OF-PROGRAM.
DATA(app) = NEW lcl_app( ).
AT SELECTION-SCREEN OUTPUT.
TRY.
app->pbo( ).
CATCH cx_root INTO DATA(lx).
MESSAGE lx TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.
Related
I'm fairly new to programming so please be patient with me. I'm trying to create a simple script in Autodesk Maya. I've created a method that sets up two check-boxes side by side (See below)...
def checkboxLayout(self, name1, text1, name2, text2, parentLayout, initState):
##create and add horizontal layout
layout = QtGui.QHBoxLayout()
parentLayout.addLayout(layout)
width = 75
name1 = QtGui.QCheckBox(text1)
layout.addWidget(name1)
name1.setMinimumWidth(width)
name1.setMaximumWidth(width)
name1.setChecked(initState)
name2 = QtGui.QCheckBox(text2)
layout.addWidget(name2)
name2.setMinimumWidth(width)
name2.setMaximumWidth(width)
And later on I've called this method twice in order to save me having to write out the same big block of code twice...
def createLayout(self):
##Layout
mainLayout = QtGui.QVBoxLayout()
mainLayout.addWidget(self.title)
mainLayout.addSpacerItem(self.titleSpacer)
mainLayout.addWidget(self.oldLabel)
self.checkboxLayout("selection_CB", "Selection", "name_CB", "Name", mainLayout, True)
mainLayout.addWidget(self.textbox1)
mainLayout.addSpacerItem(self.midSpacer)
mainLayout.addWidget(self.newLabel)
mainLayout.addWidget(self.textbox2)
self.checkboxLayout("delHistory_CB", "Delete\nHistory", "freezeTrans_CB", "Freeze\nTransforms", mainLayout, False)
self.buttonLayout = QtGui.QGridLayout()
mainLayout.addLayout(self.buttonLayout)
self.buttonLayout.addWidget(self.cancelButton, 0, 0)
self.buttonLayout.addWidget(self.okButton, 0, 1)
self.setLayout(mainLayout)
My problem is that when I try to connect a signal to it, it won't work. All the tutorials I've watched so far have only connected signals to widgets that WERE NOT created by calling a method inside another method (I realize that probably isn't the correct terminology but like I said, I'm new to this :( ) I'll post the code that I've written to try and connect the signal below. My guess was that I had to specify the method that created the check box, but I couldn't get that to work either. So how do I get this signal connected? Also feel free to correct my terminology :) Thanks to anyone who can help :)
def createConnections(self):
self.selection_CB.toggled.connect(self.checkboxLine1_ChangeState)
Where and how are you setting the variable self.selection_CB?
In your checkboxLayout function you can include a return for your check box like so:
`return [name1, name2]`
then simply assign them as you're calling the function and connect the events from there:
self.check1, self.check2 = self.checkboxLayout("selection_CB", "Selection", "name_CB", "Name", mainLayout, True)
Or if they are always being connected to the same functions, then why not just do the connection straight from checkboxLayout?
name1.stateChanged.connect(self.checkboxLine1_ChangeState)
I've one grid created on second page of page frame and linked to .PRG file for each time activate on different page. Under Activate events, each grid's column defined its own member class created under .PRG file.The problem is I couldn't able to access to each member control of grid's columns even I tried to change it but it will remain same class created under individual page's activate events.
I won't initialise the gird's column control base class on grid's init event because I need to set additive access to different .PRG file When access on different page. This problem of failed to access column member or control of grid won't be exists in form when I initalised grid's member control under grid's init events. BTW,i'm using vfp 6.
My Code under Page item Activate Events
set procedure to
set procedure to cn_pro additive
for count = thisform.page_.pages(thisform.page_.activepage).grid_list.columncount to 1 step -1
column_ = "column" + alltrim(str(count))
thisform.page_.pages( thisform.page_.activepage ).grid_list.removeobject( "&column_")
next
with thisform.page_.pages(thisform.page_.activepage).grid_list
.addobject("column1","column")
.columns(1).visible = .t.
.columns(1).bound = .t.
.columns(1).width = 75
.columns(1).header1.alignment = 2
.columns(1).header1.caption = "Mod_Qty"
.columns(1).removeobject("text1")
.columns(1).addobject("btn_qty","btn_quan")
.columns(1).currentcontrol = "btn_qty"
.columns(1).btn_qty.visible = .t.
.columns(1).btn_qty.caption = "Mod Qty"
.columns(1).sparse = .f.
endwith
create cursor tmpcur(btn_qty logical null)
use in select('tmpcur')
use in dbf('tmpcur') in 0 again alias tmpcur_
use in tmpcur
thisform.page_.pages(thisform.page_.activepage).grid_list.recordsource = ""
thisform.page_.pages(thisform.page_.activepage).grid_list.recordsource = "tmpcur_"
thisform.page_.pages(thisform.page_.activepage).grid_list.refresh()
**My class code in cn_pro.PRG file(Same example 1 problem)**
define class frm as form
procedure keypress
LPARAMETERS nKeyCode, nShiftAltCtrl
for each frm_ in _screen.forms
if alltrim(frm_.name) == "MAIN"
scan
with frm_.page_.pages( frm_.page_.activepage ).grid_list
**=>Example is here I've two record inside the grid,
**=>I want to change the property of button or access on it.**
.column1.btn_qty.enabled = .f.
**=>It will return Error message said "unknown member btn_qty" How to fix it?**
endwith
endscan
endif
endfor
endpro
enddefine
**My class code in cn_pro.PRG file(Same example 2 problem)**
define class frm as form
procedure keypress
LPARAMETERS nKeyCode, nShiftAltCtrl
for each frm_ in _screen.forms
if alltrim(frm_.name) == "MAIN"
scan
with frm_.page_.pages(frm_.page_.activepage).grid_list
**=>Example is here I've two record inside the grid,
**=>I want to change the property of button or access on it.**
.removeobject('column1')
**=>Remove entire column1 contained with** commandbutton "btn_qty"
.createobject('column1','column')
.column1.bound = .t.
.column1.text1.visible = .t.
.column1.sparse = .f.
.refresh()
**=> Previous CommandButton on column1 should be changed and
** replace with text here but It won't change and still be
** same commandbutton.Why, How to fix it?**
endwith
endscan
endif
endfor
endpro
enddefine
Hopefully anyone could solve my problem here.Thanks!
If i understand correctly, your approach will not work. You don't need to remove columns, you need to add/remove objects to the column and then set the columns current control property to the control you want.
If you want a variety of different controls to display for the same column, then you set the dynamiccurrentcontrol property to an expression that will look at a value and then return the name of the column.control that you want to display dependent upon the logical comparison in the expression.
I think I've ready found the solution, the reason why it unable detect button(control members fo grid) because it is created right after return focus to main form when you have grid created on page frame.
m.result = .t.
frm_.page_.pages(frm_.page_.activepage).btn_print.setfocus() =>to set it focus for later trigger btn_print's gotfocus
=>event,which will be able to change property's of member control of grids.
this.release =>exit "frm" class
Coding for btn_print gotfocus
if m.result=.t.
m.result = .f.
with this.parent.gid_list
.columns(1).btn_qty.enabled = .f.
endwith
endif
Struggle me for one day more until i could find out the reason and solution.
I need to update multiple targets when a link is clicked.
This example builds a list of links.
When the link is clicked, the callback needs to populate two different parts of the .html file.
The actual application uses bokeh for plotting.
The user will click on a link, the 'linkDetails1' and 'linkDetails2' will hold the script and div return from calls to bokeh.component()
The user will click on a link, and the script, div returned from bokeh's component() function will populate the 'linkDetails'.
Obviously this naive approach does not work.
How can I make a list of links that when clicked on will populate two separate places in the .html file?
################################
#views/default/test.html:
{{extend 'layout.html'}}
{{=linkDetails1}}
{{=linkDetails2}}
{{=links}}
################################
# controllers/default.py:
def test():
"""
example action using the internationalization operator T and flash
rendered by views/default/index.html or views/generic.html
if you need a simple wiki simply replace the two lines below with:
return auth.wiki()
"""
d = dict()
links = []
for ii in range(5):
link = A("click on link %d"%ii, callback=URL('linkHandler/%d'%ii), )
links.append(["Item %d"%ii, link])
table = TABLE()
table.append([TR(*rows) for rows in links])
d["links"] = table
d["linkDetails1"] = "linkDetails1"
d["linkDetails2"] = "linkDetails2"
return d
def linkHandler():
import os
d = dict()
# request.url will be linked/N
ii = int(os.path.split(request.url)[1])
# want to put some information into linkDetails, some into linkDiv
# this does not work:
d = dict()
d["linkDetails1"] = "linkHandler %d"%ii
d["linkDetails2"] = "linkHandler %d"%ii
return d
I must admit that I'm not 100% clear on what you're trying to do here, but if you need to update e.g. 2 div elements in your page in response to a single click, there are a couple of ways to accomplish that.
The easiest, and arguably most web2py-ish way is to contain your targets in an outer div that's a target for the update.
Another alternative, which is very powerful is to use something like Taconite [1], which you can use to update multiple parts of the DOM in a single response.
[1] http://www.malsup.com/jquery/taconite/
In this case, it doesn't look like you need the Ajax call to return content to two separate parts of the DOM. Instead, both elements returned (the script and the div elements) can simply be placed inside a single parent div.
# views/default/test.html:
{{extend 'layout.html'}}
<div id="link_details">
{{=linkDetails1}}
{{=linkDetails2}}
</div>
{{=links}}
# controllers/default.py
def test():
...
for ii in range(5):
link = A("click on link %d" % ii,
callback=URL('default', 'linkHandler', args=ii),
target="link_details")
...
If you provide a "target" argument to A(), the result of the Ajax call will go into the DOM element with that ID.
def linkHandler():
...
content = CAT(SCRIPT(...), DIV(...))
return content
In linkHandler, instead of returning a dictionary (which requires a view in order to generate HTML), you can simply return a web2py HTML helper, which will automatically be serialized to HTML and then inserted into the target div. The CAT() helper simply concatenates other elements (in this case, your script and associated div).
In my game, I have an __init__ function which creates a set of seven entry boxes, like so:
self.string1 = StringVal()
self.entry1 = Entry(frame, textvariable = self.string1).grid(row = 4, column = 1, sticky = W)
This is copied six more times. This works.
At the end of the game, though, I want to delete the Entry box's text, using this code I found several places online:
self.entry1.delete(0, END)
I also tried using something else I found:
if self.entry1.get():
self.entry1.delete(0, END)
These both say that self.entry1 is a NoneType object, and has no method .get() or .delete(). Just to try things out, I substituted self.entry1.get() and self.entry1.delete(0,END) with self.string1.get(), etc. I also tried substituting .delete(0, END) with .delete(0.0, END). Neither of these worked either. I do not understand what I am doing wrong.
Thanks for your help!
When you do something like this:
self.foo = Button(...).grid(...)
... Then what gets stored in self.foo is the result of the call to grid(). This will always be None. You need to separate your widget creation from the loyout in order to save a reference to the created widgets.
What I have is a table of dollar amounts, some of which are links. Example:
$0.00
$1,000.00
$1.00
How do I say this most succinctly in QTP-land?
Set desCurrencyString = Description.Create
desCurrencyString("micclass").value = NOT "Link"
I suppose I could just use a boolean value to see where the link is and somehow capture the other parts of the list, possibly like this:
Set desCurrencyString = Description.Create
desCurrencyString("text").RegularExpression = True
desCurrencyString("text").value = "\$[0-9]*"
Set arrCurrencyStrings = Page.ChildObjects(desCurrencyString)
desCurrencyString("micclass").value = "Link"
arrCurrencyStrings.Remove(desCurrencyString) 'Or something, will be editing this line later
Simply loop through a WebTable.
To get cell text, use GetCellData(Row, Col) method of WebTable object.
To get a child object contained in a cell, use ChildItem(Row, Col, MicClass, intIndex) method of WebTable object.
Neither table rows, nor cells, spans, divs, etc. can be returned by ChildObjects function as they are not truly GUI object classes. (Though, if you would need it very much you could define such custom objects, but you'd have to manually set them up in Object Repository Manager).