Can the width of the tab-header of a CTabItem be set arbitrary?
Thnx in advance!
Kind regard,
Marcus
You can try to override CTabItem, but this solution doesn't look as nice solution (nevertheless I use it):
CTabItem tabItem;
final int tabWidth = 90;
tabItem = new CTabItem( tabFolder, SWT.NONE ) {
#Override
public Rectangle getBounds( ) {
Rectangle bounds = super.getBounds();
bounds.x = 0 * tabWidth;
bounds.width = tabWidth;
return bounds;
}
};
tabItem.setText( __lang.str( this, "Tab Item I" ) );
tabItem = new CTabItem( tabFolder, SWT.NONE ) {
#Override
public Rectangle getBounds( ) {
Rectangle bounds = super.getBounds();
bounds.x = 1 * tabWidth;
bounds.width = tabWidth;
return bounds;
}
};
tabItem.setText( __lang.str( this, "Tab Item II" ) );
tabItem = new CTabItem( tabFolder, SWT.NONE ) {
#Override
public Rectangle getBounds( ) {
Rectangle bounds = super.getBounds();
bounds.x = 2 * tabWidth;
bounds.width = tabWidth;
return bounds;
}
};
tabItem.setText( __lang.str( this, "Tab Item III" ) );
No you can't do that. Not at least by any exposed API (read public methods).
A possible solution is to extend the code of CTabFolder and CTabItem.
As a workaround, you can pad the title with extra spaces
using String.format like:
cTabItem.setText(String.format("%-15s", orgTitle));
This will add extra spaces to the end of the string if its length is less than 15 characters.
Check this for more details:
https://docs.oracle.com/javase/tutorial/essential/io/formatting.html
Related
I'm currently writing a CAD-like program for logic circuits (it's my first "graphics intensive" program ever). When I place a component on the schematic, let say an AND gate (which is Region class at its root), I want to be able to interact with it (select it, change its properties, etc). So far, so good. I can click on it and everything go well. However, if I click outside of it, the mouse click event still show the component as it source(!).
Digging a bit further, I put some traces in the mouse click handler and found out that getBoundsInLocal() and getBoundsInParent() return bounds that are around 50% larger than it should be. The getLayoutBounds(), getWidth() and getHeight() do return the correct value.
The pane onto which the components are laid out is a simple Pane object, but it uses setScaleX() and setScaleY() to implement zooming capabilities. I did try to disable them, with no luck.
public abstract class SchematicComponent
extends Region {
private Shape graphicShape = null;
public Shape getGraphicShape() {
if( isShapeDirty() ) {
if( graphicShape != null ) {
getChildren().remove( graphicShape );
}
graphicShape = createShape();
markShapeDirty( false );
if( graphicShape != null ) {
getChildren().add( graphicShape );
}
}
return graphicShape;
}
abstract protected Shape createShape();
}
abstract public class CircuitComponent
extends SchematicComponent {
}
abstract public class LogicGate
extends CircuitComponent {
#Override
protected void layoutChildren() {
super.layoutChildren();
Pin outPin;
final double inputLength = getInputPinsMaxLength();
// Layout the component around its center.
// NOTE: I did try to set the center offset to 0 with no luck.
Point2D centerOffset = getCenterPointOffset().multiply( -1 );
Shape gateShape = getGraphicShape();
if( gateShape != null ) {
gateShape.setLayoutX( centerOffset.getX() + inputLength );
gateShape.setLayoutY( centerOffset.getY() );
}
/* Layout the output pins. */
outPin = getOutputPin();
if( outPin != null ) {
outPin.layout();
outPin.setLayoutX( centerOffset.getX() + getWidth() );
outPin.setLayoutY( centerOffset.getY() + getHeight() / 2 );
}
/* Compute the first input pin location and the gap between each
pins */
double pinGap = 2;
double y;
if( getInputPins().size() == 2 ) {
y = centerOffset.getY() + getHeight() / 2 - 2;
pinGap = 4;
}
else {
y = centerOffset.getY() + ( getHeight() / 2 ) - getInputPins().size() + 1;
}
/* Layout the input pins */
for( Pin inPin : getInputPins() ) {
inPin.layout();
inPin.layoutXProperty().set( centerOffset.getX() );
inPin.layoutYProperty().set( y );
y += pinGap;
}
}
}
// The actual object placed on the schematic
public class AndGate
extends LogicGate {
#Override
protected double computePrefWidth( double height ) {
// NOTE: computeMin/MaxWidth methods call this one
double width = getSymbolWidth() + getInputPinsMaxLength();
double length = 0;
width += length;
if( getOutputPin().getLength() > 0 ) {
width += getOutputPin().getLength();
}
return width; // Always 16
}
#Override
protected double computePrefHeight( double width ) {
// NOTE: computeMin/MaxHeight methods call this one
return getSymbolHeight() + getExtraHeight(); // Always 10
}
#Override
protected Shape createShape() {
Path shape;
final double extraHeight = getExtraHeight();
final double inputLength = getInputPinsMaxLength();
final double outputLength = getOutputPin().getLength();
/* Width and Height of the symbol itself (i,e, excluding the
input/output pins */
final double width = getWidth() - inputLength - outputLength;
final double height = getHeight() - extraHeight;
/* Starting point */
double startX = 0;
double startY = extraHeight / 2;
ArrayList<PathElement> elements = new ArrayList<>();
elements.add( new MoveTo( startX, startY ) );
elements.add( new HLineTo( startX + ( width / 2 ) ) );
elements.add( new ArcTo( ( width / 2 ), // X radius
height / 2, // Y radius
180, // Angle 180°
startX + ( width / 2 ), // X position
startY + height, // Y position
false, // large arc
true ) ); // sweep
elements.add( new HLineTo( startX ) );
if( extraHeight > 0 ) {
/* The height of the input pins is larger than the height of
the shape so we need to add extra bar on top and bottom of
the shape.
*/
elements.add( new MoveTo( startX, 0 ) );
elements.add( new VLineTo( extraHeight + height ) );
}
else {
elements.add( new VLineTo( startY ) );
}
shape = new Path( elements );
shape.setStroke( getPenColor() );
shape.setStrokeWidth( getPenSize() );
shape.setStrokeLineJoin( StrokeLineJoin.ROUND );
shape.setStrokeLineCap( StrokeLineCap.ROUND );
shape.setFillRule( FillRule.NON_ZERO );
shape.setFill( getFillColor() );
return shape;
}
} // End: LogiGate
// SchematicView is the ScrollPane container that handles the events
public class SchematicView
extends ScrollPane {
/* Mouse handler inner class */
private class MouseEventHandler
implements EventHandler<MouseEvent> {
#Override
public void handle( MouseEvent event ) {
if( event.getEventType() == MouseEvent.MOUSE_CLICKED ) {
processMouseClicked( event );
}
else { /* ... more stuff ... */ }
}
private void processMouseClicked( MouseEvent event ) {
Object node = event.getSource();
SchematicSheet sheet = getSheet();
Bounds local = ( (Node) node ).getLayoutBounds();
Bounds local1 = ( (Node) node ).getBoundsInLocal();
Bounds parent = ( (Node) node ).getBoundsInParent();
// At this point, here is what I get:
// node.getHeight() = 10 -> Good
// local.getHeight() = 10 -> Good
// local1.getHeight() = 15.6499996... -> Not expected!
// parent.getHeight() = 15.6500015... -> Not expected!
/*... More stuff ... */
}
}
So at this point, I'm running of clues of what is going on. Where do these getBoundsInXXX() values come from? They doesn't match with the parent's scale values either. The same goes with getWidth(): I get 24.825000... instead of 16.
Looking at this, I understand why clicking outside the component works as if I clicked on it. Its bounds are about 50% bigger than what it should be.
I googled the damn thing and search some doc for almost 2 days now and I'm still baffled. I think I understand that getBoundsInXXX() methods do their own computation but could it be off by that much? I don't thing so. My best guess is that it is something inside the createShape() method but I just can't figure what it is.
Anyone has a clue of what is going on?
Many thanks for your help.
P.S.: This is my first post here, so hopefully I did it right ;)
I think I finally found the problem :)
Basically, the Pin custom shape was drawn in the negative part of X axis (wrong calculations, my bad!). My best guess is that somehow, Java notices that I drew outside the standard bounds and then added the extra space used to the bounds, hence, adding 50% to width, which matches the length of the Pin. Drawing it in the positive region seem to have fixed the problem.
I'm not 100% sure if that is the right answer, but it make sense and it is now working has expected.
I'm trying to get the radius of a Circle Shape after I scaled it. I don't know how to do it. I'm developing a software (with javaFX library) that will let the user add Shapes (Circle, Rectangle, Squares,...)to a Panel, simply "modify" them, save the drawing and load it. I'm managing the saving/loading stuff by cycling through the Nodes the user added (there's a button to create Circle, Rectangle, ... and add it to the Panel), taking the properties I need to load them (centerX, centerY, scaleX, scaleY, ...) and, when button "save" pressed, to save them in a txt file. (stil working on loading, but my thought was to read the previous txt file and cycle it to re-create Shapes on panel in the same position, scale, rotation.)
Here's the code I wrote this is the portion of code that create circle:
public Circle createCircle(double x, double y, double r, Color color) {
Circle circle = new Circle(x, y, r, color);
circle.setCursor(Cursor.HAND);
circle.setOnMousePressed((t) -> {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
Circle c = (Circle) (t.getSource());
c.toFront();
});
circle.setOnMouseDragged((t) -> {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
Circle c = (Circle) (t.getSource());
c.setCenterX(c.getCenterX() + offsetX);
c.setCenterY(c.getCenterY() + offsetY);
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
});
return circle;
}
Here's the code i use to scale it:
public void addMouseScrolling(Node node) {
node.setOnScroll((ScrollEvent event) -> {
// Adjust the zoom factor as per your requirement
double zoomFactor = 1.05;
double deltaY = event.getDeltaY();
if (deltaY < 0){
zoomFactor = 2.0 - zoomFactor;
}
node.setScaleX(node.getScaleX() * zoomFactor);
node.setScaleY(node.getScaleY() * zoomFactor);
});
}
And this is the code of the save button:
Button btn2 = new Button("Save");
btn2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
int i=0;
for (Node node: root.getChildren()) i++;
String stringa_salvataggio[] = new String[i];
String stringa="";
i=0;
String scal_X_s, scal_Y_s, Lyt_X_s, Lyt_Y_s, width_s, height_s;
for (Node node: root.getChildren()){
String stringa_nodo = node.toString();
Double scal_X = node.getScaleX();
scal_X_s = Double.toString(scal_X);
Double scal_Y = node.getScaleY();
scal_Y_s = Double.toString(scal_X);
Double Lyt_X = node.getLayoutX();
Lyt_X_s = Double.toString(scal_X);
Double Lyt_Y = node.getLayoutY();
Lyt_Y_s = Double.toString(scal_X);
Double width = node.getLayoutBounds().getWidth();
width_s = Double.toString(scal_X);
Double height = node.getLayoutBounds().getHeight();
height_s = Double.toString(scal_X);
stringa = stringa + scal_X_s + scal_Y_s + "\n";
stringa_salvataggio[i] = stringa;
System.out.println("-------");
i++;
System.out.println("Nodo " + i + ":");
System.out.println("scalX:" + scal_X);
System.out.println("scalY:" + scal_Y);
System.out.println("LayoutX:" + Lyt_X);
System.out.println("LayoutY:" + Lyt_Y);
System.out.println("Width:" + width);
System.out.println("Height:" + height);
System.out.println(stringa_nodo);
//save on .txt
}
System.out.println(stringa_salvataggio);
}
});
As I said before, I don't know how to get the radius of Circle to recreate it on loading. Rectangles and squares aren't a problem, I can take all infos I need.
Thanks in advance.
I added the function below to change the margins for the page
at every page change.
I found the forum a method that sets the size of the page:
document.SetPageSize (New Rectangle (36.0F, 36.0F, 52.0F, PageFooter.TotalHeight))
But I do not want to change the size of the page, but those margins.
thanks
public override void OnEndPage(PdfWriter writer, Document document)
{
try
{
DataSet dsReport = new DataSet();
foreach (DataSet obj in report.arrayDs)
{
dsReport = obj;
break;
}
Single topMargin = 0;
if (document.PageNumber != 1)
{
if (report.repeatHead) //ripete l'intestazione del report su tutte le pagine di stampa
{
repeatHead(writer, document);
topMargin = 60;
}
else
{
if (document.PageNumber == 2) //ripete l'intestazione del report solo sulla second pagina dopo la copertina
{
repeatHead(writer, document);
topMargin = 60;
}
else
{
topMargin = Convert.ToSingle(dsReport.Tables["REPORT_STYLE"].Rows[0]["topMargin"]) * 10;
}
}
document.SetMargins(Convert.ToSingle(dsReport.Tables["REPORT_STYLE"].Rows[0]["leftMargin"]) * 10,
Convert.ToSingle(dsReport.Tables["REPORT_STYLE"].Rows[0]["rightMargin"]) * 10,
topMargin,
Convert.ToSingle(dsReport.Tables["REPORT_STYLE"].Rows[0]["bottomMargin"]) * 10);
}
}
catch
{ throw; }
}
Based on your clarification in the comments, you want the top margin of the first page to be 60 and the top margin of the second page to be 0.
This is shown in the following screen shot:
The Java code to achieve this looks like this:
public void createPdf(String dest) throws IOException, DocumentException {
float left = 30;
float right = 30;
float top = 60;
float bottom = 0;
Document document = new Document(PageSize.A4, left, right, top, bottom);
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
document.setMargins(left, right, 0, bottom);
for (int i = 0; i < 60; i++) {
document.add(new Paragraph("This is a test"));
}
document.close();
}
If you want to port this to C#, you need to change some lower cases into upper cases. You already knew most of the methods, for instance: I see document.SetMargins(...) in your page event.
I am trying to do something similar to this but in Android.
In Android I can extend the ProgressBar but I am doubting of how to add the TextViews on top. In iphone it was easy because I can use absolute positions, but not here.
Any ideas?
EDIT:
I decided to use SeekBar instead of ProgressBar to add the thumb drawable. I commented below. Some points to notice:
I am using hardcoded values, actually three but it can be more or less.
When the thumb is moved it moves to 50 but it should move to the different options.
I am using pixels instead of dpi. I should fix that.
I need to solve the lack of animation when the thumb moves.
My progress so far:
public class SliderFrameLayout extends FrameLayout implements OnSeekBarChangeListener {
private SeekBar mSlider;
private Context mContext;
private int mSize = 3;
private TextView[] mTextViews;
private String[] mTexts = {"Nafta", "Gas", "Gasoil"};
public SliderFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setWillNotDraw(false);
mTextViews = new TextView[mSize];
addSlider();
addTextViews();
}
private void addTextViews() {
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv;
tv = new TextView(mContext);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
tv.setText(mTexts[i]);
mTextViews[i] = tv;
addView(tv);
}
}
private void addSlider() {
FrameLayout fl = new FrameLayout(mContext, null);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
fl.setLayoutParams(params);
fl.setPadding(30, 30, 30, 0);
mSlider = new SeekBar(mContext, null);
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
//lp.setMargins(30, 30, 30, 0);
//mSlider.setPadding(30, 30, 30, 0);
mSlider.setLayoutParams(lp);
//mSlider.setMax(mSize-1);
mSlider.setThumbOffset(30);
//mSlider.setProgressDrawable(mContext.getResources().getDrawable(R.drawable.slider_track));
//mSlider.setThumb(mContext.getResources().getDrawable(R.drawable.slider_thumb));
mSlider.setOnSeekBarChangeListener(this);
//addView(mSlider);
fl.addView(mSlider);
addView(fl);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rectf = new Rect();
mSlider.getLocalVisibleRect(rectf);
Log.d("WIDTH :",String.valueOf(rectf.width()));
Log.d("HEIGHT :",String.valueOf(rectf.height()));
Log.d("left :",String.valueOf(rectf.left));
Log.d("right :",String.valueOf(rectf.right));
Log.d("top :",String.valueOf(rectf.top));
Log.d("bottom :",String.valueOf(rectf.bottom));
int sliderWidth = mSlider.getWidth();
int padding = sliderWidth / (mSize-1);
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv = mTextViews[i];
tv.setPadding(i* padding, 0, 0, 0);
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.d("SEEK", "value: " + seekBar.getProgress());
seekBar.setProgress(50);
}
}
You're already overriding onDraw, why not just draw the text strings yourself? Rather than go through the overhead of adding TextViews and messing with the padding, just use canvas.drawText to physically draw the text strings in the right place.
You can specify the style and color of the text using a Paint object:
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(r.getColor(R.color.text_color));
textPaint.setFakeBoldText(true);
textPaint.setSubpixelText(true);
textPaint.setTextAlign(Align.LEFT);
And get the exact positioning by using the measureText method on that Paint object to find what width a particular string would be when drawn on a canvas:
textWidth = (int)textPaint.measureText(mTexts[i]);
Then you can iterate over your array of text strings and draw each string in the right place.
#Override
protected void onDraw(Canvas canvas) {
int myWidth = getMeasuredWidth()-LEFT_PADDING-RIGHT_PADDING;
int separation = myWidth / (mSize-1);
for (int i = 0; i++; i < mSize) {
int textWidth = (int)textPaint.measureText(mTexts[i]);
canvas.drawText(mTexts[i],
LEFT_PADDING+(i*separation)-(int)(textWidth/2),
TOP_PADDING,
textPaint);
}
}
You'll probably want to do the measurements in onMeasure instead of onDraw, and you should probably only measure the width of each string when you change the text or the paint, but I've put it all in one place to (hopefully) make it easier to follow.
Just a try. You could put your custom progressBar inside a FrameLayout then, inside this layout, you have to add three TextViews with fill_parent as width.
Then you can align the three texts in this way: left, center and right. Your texts shouldn't overwrite and you can adjust a little their position using margins.
You can use this... not exact what you looking for... but really easy to set up and customize...
You can set the TextViews to have:
android:layout_width="0dp"
android:layout_weight="1"
This will let the android framework take care of the placing of the TextViews and save you from manually calculating the padding of each one.
Once I start drawing my own images in an Eclipse table cell, highlighting that table cell results in a strange highlight color. See for yourself:
While the transparency is actually preserved like in the first column, the highlight-blue isn't as blue as it should. Is this my fault or Eclipse's fault?
Here's the code snippet:
public class TransparentOrNot {
public static void main(String[] args) {
Display firstDisplay = new Display();
Shell firstShell = new Shell(firstDisplay);
firstShell.setText("Transparent-or-not!");
firstShell.setSize(300, 200);
firstShell.setLayout(new FillLayout());
TableViewer viewer = new TableViewer(firstShell, SWT.MULTI);
viewer.getTable().setLinesVisible(true);
viewer.getTable().setHeaderVisible(true);
TableViewerColumn tableViewerColumn = new TableViewerColumn(viewer, SWT.CENTER);
tableViewerColumn.getColumn().setText("First");
tableViewerColumn.getColumn().setWidth(150);
tableViewerColumn.setLabelProvider(new ColumnLabelProvider() {
#Override
public Image getImage(Object element) {
return ImageDescriptor.createFromFile(TransparentOrNot.class, "/red.png").createImage();
}
#Override
public String getText(Object element) {
return null;
}
});
tableViewerColumn = new TableViewerColumn(viewer, SWT.CENTER);
tableViewerColumn.getColumn().setText("Second");
tableViewerColumn.getColumn().setWidth(150);
tableViewerColumn.setLabelProvider(new CenterImageLabelProvider());
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.setInput(new String[][]{{"a", "b"}, {"c", "d"}});
firstShell.open();
while (!firstShell.isDisposed()) {
if (!firstDisplay.readAndDispatch()) {
firstDisplay.sleep();
}
}
firstDisplay.dispose();
}
static class CenterImageLabelProvider extends OwnerDrawLabelProvider {
#Override
protected void measure(Event event, Object element) {
// no-op
}
#Override
protected void paint(Event event, Object element) {
Image image = ImageDescriptor.createFromFile(TransparentOrNot.class, "/green.png").createImage();
Widget item = event.item;
Rectangle bounds = ((TableItem) item).getBounds(event.index);
Rectangle imgBounds = image.getBounds();
bounds.width /= 2;
bounds.width -= imgBounds.width / 2;
bounds.height /= 2;
bounds.height -= imgBounds.height / 2;
int x = bounds.width > 0 ? bounds.x + bounds.width : bounds.x;
int y = bounds.height > 0 ? bounds.y + bounds.height : bounds.y;
event.gc.drawImage(image, x, y);
}
}
}
Overriding erase() and not calling super.erase() helped.