I'm designing a UI with Enthought's TraitsUI, and I can't figure out how to get done what I want...
Here's what I want:
I have Items() in the view that I want to display as either English or SI units. I can change the value in the 'edit' box based on a SI/English button, but I can't figure out how to change the text of the label. For example, if I have an item 'Length, ft [ 3.28]' and convert it to SI, I'd like it to show 'Length, m [ 1.00]'. I can handle the 3.28->1.00 conversion, but can't figure out how to change the 'ft' to 'm'.
Any suggestions?
One thing I've tried is to define a string which holds the units name (like 'm' or 'ft')...then, in the item, I set the label like this:
label = 'Top, '+lengthUnits
This works fine when the view is first built, but it doesn't update the label when I change the units control. Is there some way to force the view to update with all the new values?
Here's a small py program that shows what I'm trying to do (feel free to critique my style :)). I'll also try and add in a couple of images that shows what happens:
# NOTE: This version of the code has been modified so that it works as I want it to :)
# Example trying to change text on a View...
from traits.api \
import HasTraits, Enum, CFloat, String
from traitsui.api \
import View, Group, HGroup, Item, spring
class TestDialog ( HasTraits ):
length = CFloat(1.0)
choose_units = Enum('English', 'SI')
current_units = 'English'
unit_name = String('ft')
ft_to_m = CFloat(3.28)
view = View(
Group(
HGroup(
spring,
Item(name = "length", label = 'Test length'),
Item(name = 'unit_name', style = 'readonly', show_label = False),
spring
),
HGroup(
spring,
Item(name = "choose_units"),
spring
)
),
title = 'Test Changing View Test'
)
def _choose_units_changed(self):
if self.current_units != self.choose_units:
if self.choose_units == 'SI':
self.length /= self.ft_to_m
self.unit_name = 'm'
else:
self.length *= self.ft_to_m
self.unit_name = 'ft'
self.current_units = self.choose_units
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
TestIt = TestDialog()
# put the actual dialog up...
TestIt.configure_traits()
Use a notification as described here: http://code.enthought.com/projects/traits/docs/html/traits_user_manual/notification.html
Update in response to updated question:
Right, labels are not dynamically updated. Instead, make a text field that looks like a label, e.g. with:
label_text = String('Test length, English:')
Then display it in your View with something like:
Item("label_text", style='readonly', show_label=False),
You'll probably also want to use an HGroup nested inside your (V)Group, to position it to the left of your "length" display.
Then modify label_text inside your listener.
Related
I am writing a program in Perl using Gtk3. I have a left sidebar (not using any sidebar widgets) that contains multiple tree views.
I it setup like this:
my $sidebarscrollarea = Gtk3::ScrolledWindow->new( undef, undef );
my $sidebarlabelaccounts = Gtk3::Label->new("Accounts");
$sidebarlabelaccounts->set_halign('GTK_ALIGN_START');
my $sidebarlabelincome = Gtk3::Label->new("Income Envelopes");
$sidebarlabelincome->set_halign('GTK_ALIGN_START');
my $sidebarlabelexpense = Gtk3::Label->new("Expense Envelopes");
$sidebarlabelexpense->set_halign('GTK_ALIGN_START');
# *_create_model() builds the models
my $account_tstore = account_create_model();
my $income_tstore = envelope_create_model();
my $expense_tstore = envelope_create_model();
# populate the models with another subroutine
populate_models();
my $accountslist = Gtk3::TreeView->new();
$accountslist->set_model($account_tstore);
my $incomelist = Gtk3::TreeView->new();
$incomelist->set_model($income_tstore);
my $expenselist = Gtk3::TreeView->new();
$expenselist->set_model($expense_lstore);
# Add columns to model and view via view ( Gtk3::TreeView )
account_add_columns($accountslist);
envelope_add_columns($incomelist);
envelope_add_columns($expenselist);
my $sidebarbox = Gtk3::Box->new('vertical',1);
$sidebarbox->set_border_width(5);
$sidebarbox->pack_start($sidebarlabelaccounts,0,0,5);
$sidebarbox->pack_start($accountslist,0,6,5);
$sidebarbox->pack_start($sidebarlabelincome,0,0,5);
$sidebarbox->pack_start($incomelist,0,6,0);
$sidebarbox->pack_start($sidebarlabelexpense,0,0,5);
$sidebarbox->pack_start($expenselist,0,6,0);
$sidebarscrollarea->add($sidebarbox);
The envelopeslist is very long. When I click a row from that list that is toward the bottom of the window, it scrolls so that the envelopes list at the top of the window. I do not want it to move anywhere regardless of where I click a row. Thanks for your help. I am new to all of this.
Simply adding:
$expenselist->set_can_focus(FALSE);
solves my problem.
I want to hide the "top" part of all connector labels of a diagram. For this, I tried to set up a script, but it currently hides ALL labels (also the "bottom" labels which I want to preserve):
// Get a reference to the current diagram
var currentDiagram as EA.Diagram;
currentDiagram = Repository.GetCurrentDiagram();
if (currentDiagram != null)
{
for (var i = 0; i < currentDiagram.DiagramLinks.Count; i++)
{
var currentDiagramLink as EA.DiagramLink;
currentDiagramLink = currentDiagram.DiagramLinks.GetAt(i);
currentDiagramLink.Geometry = currentDiagramLink.Geometry
.replace(/HDN=0/g, "HDN=1")
.replace(/LLT=;/, "LLT=HDN=1;")
.replace(/LRT=;/, "LRT=HDN=1;");
if (!currentDiagramLink.Update())
{
Session.Output(currentDiagramLink.GetLastError());
}
}
}
When I hide only the top labels manually (context menu of a connector/Visibility/Set Label Visibility), the Geometry property of the DiagramLinks remains unchanged, so I guess the detailed label visibility information must be contained somewhere else in the model.
Does anyone know how to change my script?
Thanks in advance!
EDIT:
The dialog for editing the detailed label visibility looks as follows:
My goal is unchecking the "top label" checkboxes programmatically.
In the Geometry attribute you will find a partial string like
LLT=CX=36:CY=13:OX=0:OY=0:HDN=0:BLD=0:ITA=0:UND=0:CLR=-1:ALN=1:DIR=0:ROT=0;
So in between LLT and the next semi-colon you need to locate the HDN=0 and replace that with HDN=1. A simple global change like above wont work. You need a wild card like in the regex LLT=([^;]+); to work correctly.
Because I use Comboboxes that may contain text entries of very long size,
which leads to the combobox increasing its width far beyond reasonable size,
I am trying to give a maximum width to the combobox.
If I am doing this like this:
class MyCombo : public Gtk::ComboBox {
private:
CellRendererText render;
public:
MyCombo() {
render.property_width_chars() = 10;
render.property_ellipsize() = Pango::ELLIPSIZE_END;
pack_start(render, true);
}
};
The result will be an empty cell of the desired width, which seems logical since I did not specify which column to show. But how can I do this with that attempt? Using pack_start will just bypass the renderer...
Another approach is this one:
class MyCombo : public Gtk::ComboBox {
private:
CellRendererText render;
public:
MyCombo() {
pack_start(render, true);
set_cell_data_func(render, sigc::mem_fun(*this, &MyCombo::render_iter));
}
void render_iter(const TreeModel::const_iterator& iter) {
Glib::ustring data = get_string_from_iter(iter);
int desired_width_chars = 10; //for example
render.property_text() = ellipsize_string(data, desired_width_chars);
}
};
Using that approach, it works, but the text in the popup (what opens up when u click the combobox) is also shortened which is not what I want (obviously the user should be able to read the whole string and I dont care about the popup widht.)
Can you please help me with this? I would be happy for any advice/alternative solutions.
Regards tagelicht
NOTE: set_wrap_width is a function that wraps the total number of entries in the combo box over a number of columns specified; it does not answer the question.
Using set_wrap_width(1) | Using set_wrap_width(5)
Following Noup's answer as a guide I managed to get the below code; which directly answers the question and its requirements (C++/Gtkmm).
// Get the first cell renderer of the ComboBox.
auto v_cellRenderer = (Gtk::CellRendererText*)v_comboBox.get_first_cell();
// Probably obsolete; Sets character width to 1.
v_cellRenderer->property_width_chars() = 1;
// Sets the ellipses ("...") to be at the end, where text overflows.
// See Pango::ELLIPSIZE enum for other values.
v_cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_END;
// Sets the size of the box, change this to suit your needs.
// -1 sets it to automatic scaling: (width, height).
v_cellRenderer->set_fixed_size(200, -1);
Result (image):
Result of code
BE AWARE: Depending on where you perform the above code; either all the cells will be the same size, or just the box itself (intended).
From experimenting, I've found:
In the parent object constructor: All cell sizes are the same.
In a separate function: Only the first cell (the box) is affected.
I'd recommend you put the code in a function that's connected to the comboBox's changed signal, such as:
v_comboBox.signal_changed().connect(sigc::mem_fun(*this, &YourClass::comboBox_changedFunction));
This may be what you are looking for:
cell_renderer_text.set_wrap_width(10)
This is for Python, but you get the idea :-)
Unfortunately, the documentation is scarce. I found this by poking around in Anjuta/Glade.
Edit:
the docs are here. They are not overly helpful, but they do exist.
As an alternative, the following works for me without having to set wrap_width nor to subclass ComboBox (in Gtk#):
ComboBoxText cb = new ComboBoxText();
cb.Hexpand = true; //If there's available space, we use it
CellRendererText renderer = (cb.Cells[0] as CellRendererText); //Get the ComboBoxText only renderer
renderer.WidthChars = 20; //Always show at least 20 chars
renderer.Ellipsize = Pango.EllipsizeMode.End;
Note: I'm using Expand to use space if it's available. If you just want to keep the combo box on a fixed width, just remove that bit.
On our site, other admins add images via the "Resources" tab of the main page. These images are displayed as Banners in a Slider on the main page. However, now they want the ability to add links to specific images.
My first thought on this (after receiving some help on making a loop for images to be added to the page) was to perhaps let them be able to add the link to either the "Title" or "Caption" spot I saw there. And later, on the slider "create" function, pull the said data from the image and make <a> wrap around the image before the slider finished building. I've already tested the slider plugin with this functionality, and that would work fine, however, I can't seem to pull anything from the "Title" or "Caption" and add it to the image in any way.
My other thought would be, is there a way to extend the back end to give them an actualy spot to paste links on images so that I may pull that and wrap the image via the typoscript, or can i pull from caption and wrap image in <a> "if" the link is available.
In other words, does typoscript have a type of "if" statement? What I ahve so far, thanks to maholtz is as follows:
#BANNER IMAGES LOOP BEGIN
page.10.marks.topimage = TEXT
page.10.marks.topimage {
# retrieve data
data = levelmedia: -1, "slide"
override.field = media
# we have some filenames in a list, let us split the list
# and create images one by one
# if there are five images selected, the CARRAY "1" will be executed
# five times where current is loaded with only one filename
split {
# the images are separated via ","
token = ,
# you can do funny stuff with options split, f.e. if you want to give first
# and last image a different class... but thats another topic;)
# we just say, render every splitted object via CARRAY "1"
cObjNum = 1
1 {
# just render the single image,
# now there should be one filename in current only
10 = IMAGE
10 {
file.import.wrap = fileadmin/user_upload/|
file.import.current = 1
border = 0
file.height = 670
file.width = 1800
altText = Banner
titleText = Banner
# attempt to add link to image if available
caption.1.typolink.parameter.field = image_link
caption.1.typolink.parameter.listNum.stdWrap.data = register:IMAGE_NUM_CURRENT
}
}
}
wrap = <div id="slides">|</div>
}
#BANNER IMAGES LOOP END
I was thinking perhaps I could do something like:
10 {
file.import.wrap = fileadmin/user_upload/|
file.import.current = 1
border = 0
file.height = 670
file.width = 1800
altText = Banner
titleText = Banner
# attempt to add link to image if available
caption.1.typolink.parameter.field = ???
caption.1.typolink.parameter.listNum.stdWrap.data = register:IMAGE_NUM_CURRENT
}
But as you can see, I'm stumped on how that might even work right. Can anyone help point me the right way.
As before mentioned, perhaps I could do ONE of two things:
Pull link from "Title" or "Caption" and add it to the IMAGE Date on output so that I can use that client side to wrap the image in appropriate a tag, |OR|
Pull link from there and use typoscript to wrap the image in a tags
When accessing the ressources via levelmedia = slide you're not directly accessing the FAL table. Therefore you have to load it again to access the fields you want. We solved exactly the problem you have with the following code. Insert it inside your 1 after 10 = IMAGE.
typolink{
parameter{
cObject = RECORDS
cObject{
source.current = 1
tables = sys_file_reference
conf.sys_file_reference = TEXT
conf.sys_file_reference.field = #title or description
}
}
}
I have a label which i need to create as per the size of my record
like if there are 2 records from database , my method should check and create 2 new labels at runtime , if 10 records there should be 10 labels to be created at run time
I am able to create 10 new labels at run time but how can i name them differently
some thing like
for (int i =0;i<array.size();i++)
{
Label lbl = new Label();
}
in this way there are 10 labels and showing perfectly , but all ten have the same name i.e lbl can this name could also be change like lbl1,lbl2,lbl3...
is it possible in GWT
Thanks
The thing you want to do isn't poosible in any programming language.
The solution you are searching for is storing them inside a list and then access the labels via the index. Eg. if you want the first label you say List[0]
GWT supports such list, the easiast for you to use ist the ArrayList!
here is some more or less pseudo code:
ArrayList<Label> labelList = new ArrayList<Label>();
for (int i =0;i<array.size();i++)
{
Label lbl = new Label();
labelList.add(lbl);
}
...
//the first item has the index 0!
Label lbl1 = labelList.get(0);
..
//doing stuff with the first label
...
//getting the secont label
Label lbl2 = labelList.get(1);
...
//you get the idea right
...