Exposing Custom Control Properties - visual-studio

I am developing a new custom control in VisualStudio and wonder whether you can limit the property selection at design time.
To illustrate the problem, there are two properties that rely on each other – orientation and textside. The control itself is rectangular and the orientation can be either vertical or horizontal. What I want is to limit the textside property so that if the orientation is vertical the textside can only be left or right and if orientation is horizontal the textside can only be top or bottom.
Clearly you can do this at runtime within a set property method by checking other properties but what I would like to do this within the property window as design time so there is no chance of someone choosing the wrong combination of properties and then nothing or the wrong information is displayed when the project is run.
Currently I have this:
public enum VerticalTextSide { Left, Right }
public enum HorizontalTextSide { Top, Bottom }
public enum TextSide { }
public enum Orientation { Vertical, Horizontal }
private VerticalTextSide vts;
private HorizontalTextSide hts;
private TextSide db;
private Orientation or;
public TextSide textSide
{
get
{
if (or == Orientation.Vertical)
{
[need help!!]
}
else
{
[need help!!]
}
}
set
{
[need help!!]
}
}
public Orientation orientation
{
get
{
return or;
}
set
{
or = value;
}
}
Where I need help is to return and set the enum values depending on the orientation chosen. Maybe there is another way, perhaps?
Hopefully this is doable?
Thanks

Not sure how to limit it at design time -- I've seen compile-time and run-time checking.
However, you may want to consider simplifying your enumerations by combining Orientation and TextSide.
For instance, System.Windows.Forms.TabControl has Alignment property (TabAlignment enum) which specifies Top, Bottom, Left and Right. Implicit in this Horizontal/Vertical.
By doing this, you simplify the interface and remove the possibility for error and invalid combinations.

The trouble is with that is that this will be taken futher and include something like text direction where you can have LeftToRight or RightToLeft either of which are acceptable for a horizontal control but not for a vertical control where you may want TopToBottom or BottomToTop!!
Is the only way to add properties to a control via a getter/setter type approach?
Is there really no way of dynamically changing properties which are dependent upon others? This seems to be a big shortfall.

I know this probably seems a bit clumsy but what about not using Left/Right or Up/Down but just Position1/Position2? For example in a horizontal setup Position1 would be Left (at least when thinking about LeftToRight) and in vertical setup Position2 would be Top (assuming TopToBottom).
You could then also forget about TopToBottom/BottomToTop or LeftToRight/RightToLeft but just use a boolean called something like IsReverseOrder.

Related

How can I add an PdfFormField using IText 7 at the current page position

We have been able to add a PdfFormField at a specific location on the page using the following Scala code snippet.
val form = PdfAcroForm.getAcroForm(document.getPdfDocument(), true)
val nameField = PdfFormField.createText(document.getPdfDocument(), new Rectangle(data.x, data.y, data.width, data.height), data.formName, data.formText)
form.addField(nameField)
However, what we would like to be able to do is add it after the last Paragraph on the page that we inserted. (i.e. This field just comes directly after). Is there a way that we can derive the proper rectangle, or is there an easier way?
Thanks
There is currently no out-of-the-box way to add fields to layout, but iText team is considering implementing this functionality.
Meanwhile, there are easy ways to achieve your goal, and there are a few of them.
My examples will be in Java, but I assume you will easily be able to use them in Scala.
The first approach is just to get the bottom position of the paragraph you have added and add your field with respect to that position. The bottom position of the last paragraph happens to be the top position of the rest of available box of content on the page (area), which converts to the following code:
Document doc = new Document(pdfDoc);
doc.add(new Paragraph("This is a paragraph.\nForm field will be inserted after it"));
Rectangle freeBBox = doc.getRenderer().getCurrentArea().getBBox();
float top = freeBBox.getTop();
float fieldHeight = 20;
PdfTextFormField field = PdfFormField.createText(pdfDoc,
new Rectangle(freeBBox.getLeft(), top - fieldHeight, 100, fieldHeight), "myField", "Value");
form.addField(field);
The part you are interested in is
Rectangle freeBBox = doc.getRenderer().getCurrentArea().getBBox();
which gives you the rectangle where the content is not placed yet.
Note, however, that this approach will not affect the following paragraphs after you the one after which you want to add the form field, which means this form field and the content might overlap.
Do deal with this situation, you might want to take advantage of possibility to create custom layout elements in iText7.
Which, in turn, is converted to the following code:
private static class TextFieldRenderer extends DivRenderer {
public TextFieldRenderer(TextFieldLayoutElement modelElement) {
super(modelElement);
}
#Override
public void draw(DrawContext drawContext) {
super.draw(drawContext);
PdfAcroForm form = PdfAcroForm.getAcroForm(drawContext.getDocument(), true);
PdfTextFormField field = PdfFormField.createText(drawContext.getDocument(),
occupiedArea.getBBox(), "myField2", "Another Value");
form.addField(field);
}
}
private static class TextFieldLayoutElement extends Div {
#Override
public IRenderer getRenderer() {
return new TextFieldRenderer(this);
}
}
Then you will just need to add the elements in a fancy way:
doc.add(new Paragraph("This is another paragraph.\nForm field will be inserted right after it."));
doc.add(new TextFieldLayoutElement().setWidth(100).setHeight(20));
doc.add(new Paragraph("This paragraph follows the form field"));
In short, what we have done here is that we created a custom dummy Div element (which is an analogue of HTML's div), which will occupy area during laying out, but we defined custom #draw() operator for this element so that form field is inserted right when we know the exact position where we want to do it.
You can find the complete code of the sample here. Note, however, that the link may change as samples repository is under reorganization now.

How to draw horizontal line in blackberry

I tried following code for draw a single line horizontal line but it is not working. i am not getting what is the problem.
HorizontalFieldManager horline = new HorizontalFieldManager()
{
protected void paint(Graphics graphics)
{
super.paint(graphics);
graphics.setColor(Color.RED);
graphics.drawLine(5, 21,10, 20);
}
};
There's at least a couple problems here:
Extent
The extent of a field (or manager) is basically the size of that field on screen. This size is normally set by a Field object in its layout() method, or by a Manager object in its sublayout() method. The problem is that your HorizontalFieldManager does not override these methods to set the size (by calling setExtent()), and it doesn't look like you add any fields to the manager. So, I believe your horline manager object simply has a size of {0, 0}. Drawing outside its extent doesn't do anything.
Manager vs Field
Manager classes are containers for fields. In this case, all you have is a line. I would definitely not use a Manager (including HorizontalFieldManager) for this, since you're not putting any fields into it, and there is overhead to adding Manager objects. Use a lighter-weight Field, or maybe even modify the paint() or paintBackground() method on whatever class contains this code ... you don't show us that, so I can't say for sure.
If you want to represent the line with a Field, then this will work:
Field line = new Field() {
protected void layout(int width, int height) {
setExtent(20, 21);
}
protected void paint(Graphics g) {
int oldColor = g.getColor();
g.setColor(Color.RED);
g.drawLine(5, 21,10, 20);
g.setColor(oldColor);
}
};
add(line);
Note that I am setting the extent to width=20, height=21, because those are the maximum coordinates you pass to drawLine(). Also, because your y values are 20 and 21, this isn't actually a truly horizontal line.
add()
This might have simply been left out of the code you show to keep the question short, but whether you use a Manager or a Field, you do need to remember to call add() for your field/manager object. Objects created, but not added to a screen, will never show. In your case, the setExtent() problem would also have caused this problem.
Update:
As Dinesh shows in his answer, you could also solve the problem by using SeparatorField. However, I believe that only gives you purely horizontal/vertical lines. Because of the coordinates in your code, I wasn't sure if you needed the ability to draw lines of any orientation ... if you do, then overriding paint() is necessary. If not, use SeparatorField ... but hopefully, you learned something from this answer, too :).
Use this
HorizontalFieldManager horline = new HorizontalFieldManager()
{
protected void paint(Graphics graphics)
{
super.paint(graphics);
graphics.setColor(Color.RED);
}
};
horline.add(new SeparatorField(SeparatorField.LINE_HORIZONTAL|SeparatorField.VISUAL_STATE_FOCUS));

Tools/Guide to Creating an Image Looper in GWT

I'm setting out to create a weather model display tool (web application), and from what I've seen, I'm really liking the idea of using Google Web Tools, and especially the SmartGWT toolkit. My one biggest sticking point at this point is finding some way to create a sort of image "looper" (displaying all images in a particular "set" one after another, not unlike a slide show). For reference, I need functionality (at least on a basic level) similar to this: http://rapidrefresh.noaa.gov/hrrrconus/jsloop.cgi?dsKeys=hrrr:&runTime=2012053007&plotName=cref_sfc&fcstInc=60&numFcsts=16&model=hrrr&ptitle=HRRR%20Model%20Fields%20-%20Experimental&maxFcstLen=15&fcstStrLen=-1&resizePlot=1&domain=full&wjet=1 (though it certainly need not be exactly like that).
Does anyone know of (ideally) some sort of GWT module that can do image looping? Or if not, does it sound like something an intermediate programmer could figure out without too much trouble (I'm willing to accept a challenge), even if I've never explicitly used GWT before? I'm sure I could whip together something that pulls each image in as it goes through a loop, but prefetching them would be even more ideal.
Please comment if you need clarification on anything!
As far as I'm aware there's not a pre-fab solution to do this, although maybe SmartGWT has something I don't know about. In any case, it won't be too hard to roll your own. Here's some code to get you started:
public class ImageLooper extends Composite {
// List of images that we will loop through
private final String[] imageUrls;
// Index of the image currently being displayed
private int currentImage = 0;
// The image element that will be displayed to the user
private final Image image = new Image();
// The Timer provides a means to execute arbitrary
// code after a delay or at regular intervals
private final Timer imageUpdateTimer = new Timer() {
public void run() {
currentImage = (currentImage + 1) % images.length;
image.setUrl(imageUrls[currentImage]);
}
}
// Constructor. I'll leave it to you how you're going to
// build your list of image urls.
public ImageLooper(String[] imageUrls) {
this.imageUrls = imageUrls;
// Prefetching the list of images.
for (String url : imageUrls)
Image.prefetch(url);
// Start by displaying the first image.
image.setUrl(imageUrls[0]);
// Initialize this Composite on the image. That means
// you can attach this ImageLooper to the page like you
// would any other Widget and it will show up as the
// image.
initWidget(image);
}
// Call this method to start the animation
public void playAnimation() {
// Update the image every two seconds
imageUpdateTimer.scheduleRepeating(2000);
}
// Call this method to stop the animation
public void stopAnimation() {
imageUpdateTimer.cancel();
}
}
One annoying thing with this implementation is that you have no way of knowing when your list of images has finished loading; Image.prefetch doesn't have a callback to help you here.

Prefuse: Adding labels to edges?

In my prefuse visualization I want to add label to edges. I followed some examples proposed here on SO, but I can't bring it to work:
I use this Renderer for my edges:
private class CustomEdgeRenderer extends LabelRenderer {
private EdgeRenderer edgeRenderer = new EdgeRenderer();
#Override
public String getText(VisualItem item) {
System.out.println("edgerenderer");
return "test";
}
#Override
public void render(Graphics2D g, VisualItem item) {
edgeRenderer.render(g, item);
item.setTextColor(BLACK);
}
}
The problem now is, that the text isn't displayed, but the edges are drawn in a weird form. That is they aren't correctly drawn. If I don't overwrite render, then the text is drawn, but no edges. How can i make this work?
Following the architecture of prefuse you would create a separate group of visual items for the labels, so called DecoratorItem.
An example can be found in the TreeMap demo:
https://github.com/prefuse/Prefuse/blob/master/demos/prefuse/demos/TreeMap.java
Another more ad-hoc solution:
Extend EdgeRenderer.
Take care of drawing the label in the render method.
Call super.render to let prefuse draw the edge.
You could check this question:
Displaying edges labels in prefuse (java) graphs
Google send me here and the previous questions, and looking for some code, I recently found the following version and runs ok.
http://netgrok.googlecode.com/svn-history/r2/trunk/src/test/AggregateDecoratorDemo.java
Regards.

Touch event handling in Blackberry

I try to implement simple touch event handling on Blackberry 9550 emulator, but it doesn't work. Actually, touchEvent never gets called, 'cos no text ever appears in the console. Also, I get an annoying "Full Menu" which appears on touching the screen.
Here's the code:
package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EventInjector.TouchEvent;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.VirtualKeyboard;
import net.rim.device.api.ui.container.MainScreen;
public class MyScreen extends MainScreen
{
public MyScreen()
{
super(NO_SYSTEM_MENU_ITEMS);
getScreen().getVirtualKeyboard().setVisibility(VirtualKeyboard.HIDE_FORCE);
add(new HandleTouch());
}
class HandleTouch extends Field {
protected void layout(int width, int height) {
setExtent(width, height);
}
public void paint(Graphics graphics) {
graphics.drawBitmap(0, 0, this.getWidth(), this.getHeight(), Bitmap.getBitmapResource("bg.png"), 0, 0);
}
public boolean isFocusable() { return true;}
protected boolean touchEvent(TouchEvent message) {
switch( message.getEvent() ) {
case TouchEvent.CLICK:
System.out.println("----------------------------->CLICK");
return true;
case TouchEvent.DOWN:
System.out.println("----------------------------->DOWN");
return true;
case TouchEvent.MOVE:
System.out.println("----------------------------->MOVE");
return true;
}
System.out.println("PRINT ME SOMETHING IN ANY CASE");
return false;
}
public HandleTouch() {
}
}
}
1). First of all, with this code
protected void layout(int width, int height) {
setExtent(width, height);
}
you are actually setting a VERY large size of the field. This because the BB UI framework passes max available/possible dimentions to layout(int width, int height) so the field should use some part within the passed values. In this specific case the width will be the width of the display (360 px) and the height is the max possible height of the VerticalFieldManager (the one your are adding screen fields to, it is implicitly present in the screen's internals) (1073741823 px). So, finally this may result in a very large Bitmap object that is required with the field in order to be painted and you can get an uncaught error "Bitmap is too large" (I did on Storm 9530).
So, the layout() should use some relatively small values, e.g.:
protected void layout(int width, int height) {
setExtent(Math.min(width, 360), Math.min(height, 480));
}
2).
Actually, touchEvent never gets called
Well, actually it does get called. To see that you should simply touch (versus click). Left button of the mouse simulates clicks (a sequence of TouchEvent.DOWN > TouchEvent.CLICK > TouchEvent.UNCLICK > TouchEvent.UP), right button simulates touches (a sequence of TouchEvent.DOWN > TouchEvent.UP).
3).
Also, I get an annoying "Full Menu" which appears on touching the screen.
This is because your field does not consume TouchEvent.UNCLICK event. For instance, with this code your field will not show the popup:
protected boolean touchEvent(TouchEvent message) {
return true;
}
But, that is a bad solution for the popup. It is better to understand what really causes the popup. If TouchEvent.UNCLICK event is not consumed then BB UI framework calls getContextMenu(int instance) and makeContextMenu(ContextMenu contextMenu, int instance) methods of the field. So in order to disable the popup (which is actually a ContextMenu created by the getContextMenu(int instance) you should override the getContextMenu(int instance) to be smth like this:
public ContextMenu getContextMenu(int instance) {
// just in case check if a context menu is requested
// in order not to disable other types of menu
boolean isContextMenu = (Menu.INSTANCE_CONTEXT == instance);
return isContextMenu ? null : super.getContextMenu(instance);
}
4). Finally I'd recommend to not change native/default behavior of touchEvent(TouchEvent message) method. You can just watch/log it, but don't change (always call its super version). This is because touch events handling is more complicated than it may look at first. It is very easy to get a tricky bug here. I do believe most programmers should not change the native behavior of touchEvent(TouchEvent message) unless they really want to create some custom UI component to work with touch gestures. Normally they just want to react on a click (to behave as a ButtonField), however for that you can simply override navigationClick(int status, int time) or navigationUnclick(int status, int time). The BB UI framework will call those methods when user clicks your field on a touch screen.
I would like to add extra info to Arhimed's answer, since this seems to be a landing page for googling touch events...
My experiences are not to contradict him, but to add possible solutions for future readers. I am using BB OS 5.0. My experiences have been with the Storm simulator, and a Torch device. My app was originally written for OS 4.5, so it might be running in some sort of compatibility mode.
1) As explained in his point 4, a Touch Event gets passed along to a Navigation Click event, if touchEvent(TouchEvent) returns false. If navigationClick(int, int) returns false, this prompts the system to display a ContextMenu.
2) On my system, I could not find a method getContextMenu(int). So I could not test his point 3. I presume this gets added in BB6 or later.
3) I did find getContextMenu() - i.e. it takes no parameters. I tried to override that method to return null.
The strange thing is that this method only gets called after the initial context menu popup is shown! The initial context menu popup (?) gets shown, with a button on it for "Full Menu". When that button is pressed, this method gets called, and can be used to populate the MainMenu that appears. ... strange...
However, it means that overriding that method did not solve my problem.
4) I was unable to get a solution by returning true in touchEvent(TouchEvent). I agree that this would have been bad form (hack), but I have learnt to hack a lot on the BB platform. However, scrolling list fields need to have the touch event passed up, so that the scroll works.
5) Eventually I found something similar to the OP's problem with TouchEvent.UNCLICK. It has taken me 18 months to find the method navigationUnClick(int, int). Similar to my point 1 above, an unhandled UNCLICK becomes a navigationUnClick(int, int) call, which can also lead to the context menu being shown.
So by adding similar logic to both navigationClick(int, int) & navigationUnClick(int, int), I was able to get my lists & touches to interact nicely.
This is just supplemental info, that may add to the accepted anser.

Resources