I wrote an Eclipse PyDev plugin, and I'm trying to port it to PyCharm, but I can't find an easy way to display a text view next to the Python source code. Is there any way easier than copying the PsiAwareTextEditorImpl class and all its helpers?
I got the splitter control working so I can display something next to the Python source code. In this prototype branch, I displayed a text editor next to the Python editor. Then I created a text file for each Python file to hold the display text, but that displays the text file's name, and it would be a pain to manage a bunch of temporary files.
I stepped through the standard editor class, PsiAwareTextEditorImpl, and found that it has a ton of helper classes, and eventually calls EditorPainter.paintTextWithEffects(). Here are some of the things it does to paint text:
private void paintTextWithEffects(Graphics2D g, Rectangle clip, int startVisualLine, int endVisualLine) {
final CharSequence text = myDocument.getImmutableCharSequence();
// ...
VisualLinesIterator visLinesIterator = new VisualLinesIterator(myEditor, startVisualLine);
while (!visLinesIterator.atEnd()) {
int visualLine = visLinesIterator.getVisualLine();
if (visualLine > endVisualLine || visualLine >= lineCount) break;
int y = visLinesIterator.getY();
final boolean paintSoftWraps = paintAllSoftWraps ||
myEditor.getCaretModel().getLogicalPosition().line == visLinesIterator.getStartLogicalLine();
final int[] currentLogicalLine = new int[] {-1};
paintLineFragments(g, clip, visLinesIterator, y + myView.getAscent(), new LineFragmentPainter() {
#Override
public void paintBeforeLineStart(Graphics2D g, TextAttributes attributes, int columnEnd, float xEnd, int y) {
// ...
}
#Override
public void paint(Graphics2D g, VisualLineFragmentsIterator.Fragment fragment, int start, int end,
TextAttributes attributes, float xStart, float xEnd, int y) {
// ...
}
#Override
public void paintAfterLineEnd(Graphics2D g, Rectangle clip, IterationState iterationState, int columnStart, float x, int y) {
// ...
}
});
visLinesIterator.advance();
}
ComplexTextFragment.flushDrawingCache(g);
}
That seems like a ton of work if I have to reproduce that, so is there some existing component that I can use to display a block of text that isn't coming from a file? Should I be creating my own instance of DocumentImpl and somehow wiring that to an editor?
Here's what the Eclipse plugin looks like with the Python code on the left, and the text display on the right.
You can create instance of LightVirtualFile, fill with any content and display in editor as file of existing type or your custom type.
Related
I am writing a board game which has a 20x20 grid.
This is in my board class:
private final Position[][] grid = new Position[GRID_SIZE][GRID_SIZE];
each position has :
public class Position {
private final Coordinates pos;
private Player player;
private final static double RECTANGLE_SIZE = 40.0;
private final Rectangle rect = new Rectangle(RECTANGLE_SIZE, RECTANGLE_SIZE);
}
so basically I have 20x20 Positions and each positions has a Rectangle
This is what I do to display the grid
for (int cols = 0; cols < GRID_SIZE; ++cols) {
for (int rows = 0; rows < GRID_SIZE; ++rows) {
grid.add(gameEngine.getBoard().getGrid()[cols][rows].getRect(), cols, rows);
}
}
Anyway, the grid is initialized and works properly. What I want to do is to make the rectangle objects clickable and to be able to return their Coordinates when they are clicked.
This is how I handle the mouse click
private void setUpRectangle() {
rect.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
rect.setFill(Color.BLACK);
}
});
}
What this code does is to change the color of the rectangle to black, but how could I return the Coordinates.
Basically, I can edit the onclick function to return the coordinates of this position, but how can I acquire them later?
This is not a JavaFX question as much as it is a design question. You have a container (Position) of 2 objects (Coordinates and Rectangle) and you want one of them to know about the other. That is, the rectangle should know the coordinates of its position.
There are a few approaches here, and depending on the bigger picture, one might be better than the others. James_D mentioned a couple in a comment.
Keep a reference of the position object in the rectangle object. This is useful if rectangle needs to access various datum in the container from various places. You would do something like rectangle.getPosition().getCoordinates() or .getPlayer().
Keep a reference of the coordinates object in the rectangle object. This is a more specific approach of 1 useful if you only need that object. You would do something like rectangle.getCoordinates().
Pass the coordinates to your setUpRectangle method. This is useful if you rectangle doesn't need access to this data from various places, it's a local solution. Then in the handle method you would return the coordinates you passed to setUpRectangle, though we can't see what class this method is in.
Use external help. You can keep something like Map<Rectangle, Coordinates> and then call map.get(rectangle). You can hide this map in a method Coordinates getCoordinatesForRectangle(Rectangle rectangle) instead of calling it directly.
You could store this data as userData (or use properties in case userData is preserved for something else in your program):
private final Rectangle rect;
public Position() {
rect = new Rectangle(RECTANGLE_SIZE, RECTANGLE_SIZE);
rect.setUserData(this);
}
rect.setOnMouseClicked((MouseEvent event) -> {
Position pos = (Position) ((Node) event.getSource()).getUserData();
...
});
You could also use a listener that knows about the position:
class CoordinateAwareListener implements EventHandler<MouseEvent> {
private final int coordinateX;
private final int coordinateY;
public CoordinateAwareListener(int coordinateX, int coordinateY) {
this.coordinateX = coordinateX;
this.coordinateY = coordinateY;
}
#Override
public void handle(MouseEvent event) {
// do something with the coordinates
}
}
So far i tried so many different things to make this work. I can't seem to understand why this shouldn't work.
I have a class called StatusRect.java.
This class returns a rectangle when a new object is being made with the method makeRectangleStatus.
The idea is to color this rectangle every time an integer becomes a certain value.
In the class StatusRect.java the method changeIntFlag is invoked from another class. Here the integer is being changed. That works.
Now I just want the color of the rectangle to change in this StatusRect.java class.
The main question is actually can this color be set inside this StatusRect.java class, or can it only be done outside this class?
The rectangle object is being made in the Stage of the application like below. There the color red is given as a parameter.
Any help here is greatly appreciated.
public void start(Stage stage) throws Exception {
Rectangle rec = new StatusRect().makeRectangleStatus(50, 700, 20, 20, "red", "black", "btnObj1", 7, 0);
}
StatusRect class:
public class StatusRect {
private String ColorStatusOn;
private String ColorStatusOff;
private int IntFlag;
Rectangle rec = new Rectangle();
public Rectangle makeRectangleStatus (double x, double y, double Witdh, double Height, String ColorStatOn, String ColorStatOff, String BtnId, int SetIntStatus, int Current){
rec.setLayoutX(x);
rec.setLayoutY(y);
rec.setWidth(Witdh);
rec.setHeight(Height);
ColorStatusOn = ColorStatOn;
return rec;
}
public void changeIntFlag(int iEnabled) {
if(IntFlag == iEnabled) return;
IntFlag = iEnabled;
System.out.println("VALUE CHANGED!!!: " + IntFlag);
if (IntFlag == 7){
//this is being triggerd every time the int Flag value becomes "7"
System.out.println("SAME NUMBER: SET COLOR RECTANGLE TO red");
//Why doesnt the color change here??
rec.setStyle("-fx-fill:" + ColorStatusOn);
}
}
}
}
You can change your makeRectangleStatus method (and if it is necessary your Rectangle class adding some setters/getters) and set the colour of this.rec directly inside makeRectangleStatus. For instance, if you want that your Rectangle instance goes to ColorStatOn string, try this:
public void makeRectangleStatus (double x, double y, double Witdh, double Height, String ColorStatOn, String ColorStatOff, String BtnId, int SetIntStatus, int Current){
rec.setLayoutX(x);
rec.setLayoutY(y);
rec.setWidth(Witdh);
rec.setHeight(Height);
rec.setColorStatOn(ColorStatOn);
}
Besides pay attention: you don't need to return anything in makeRectangleStatus since you are using this.rec object.
What I noticed is that all the changes of styles from objects, rectangles buttons,etc work with events. Like action event, move, touch etc.
So when an action is true then something is changed. Just making a set method and setting a value doesnt do anything. You have to evaluate the value and add for example a changeproperty listener to it. Like with a slider, when the value of the property of the slider changes, and binding it. Objects are created only once.
I tried to do this like below. I understood that the method called "changed" is invoked when the value of the property changes, but sadly that doesnt work.
I think this is the way it should work, but Iam no expert.
IntegerProperty currentvalue = new SimpleIntegerProperty(IntFlag);
currentvalue.addListener(new ChangeListener<Number>(){
#Override
public void changed(ObservableValue <? extends Number>
observableValue, Number oldValue, Number newValue){
System.out.println("CHANGED, LISTENER TRIGGERD!!!!" +newValue);
}
});
So, I have this JTexrtArea which is almost perfect for my needs. The only thing wrong with it is the line spacing. I can't set it. (Why not JTextPane? Because spacing CAN be changed in JTextArea and JTextArea is way lighter thatn JTextPane, and I have a bunch of those in my program).
I have asked this question before, and this is the answer that I got from user StanislavL:
To override JTextArea's line spacing take a look at the PlainView (used to render PLainDocument).
There are following lines in the public void paint(Graphics g, Shape a) method
drawLine(line, g, x, y);
y += fontHeight;
So you can adapt the rendering fixing y offset.
In the BasicTextAreaUI method to create view. Replace it with your own implementation of the PlainView
public View create(Element elem) {
Document doc = elem.getDocument();
Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
// build a view that support bidi
return createI18N(elem);
} else {
JTextComponent c = getComponent();
if (c instanceof JTextArea) {
JTextArea area = (JTextArea) c;
View v;
if (area.getLineWrap()) {
v = new WrappedPlainView(elem, area.getWrapStyleWord());
} else {
v = new PlainView(elem);
}
return v;
}
}
return null;
}
I grasp the general idea of what he's telling me to do, but I don't know how to do it.
Also, I wouldn't like to override the default JTextArea "property", I'd like to have a choice - to use the default one or to use a custom one.
Only change in JTextArea code would be from
y += fontHeight,
to
y+= (fontHeight +(or -) additionalSpacing).
How do I achieve this?
Which classes do I use/copy?
Where do I put them?
How do I make them usable?
How do I get the whole thing working?
If you think this is too specific to be useful, maybe someone could write a general tutorial on how to create a custom swing component based 100% on an existing one. Then someone could easely change some values to better adjust it to it's needs.
I am simply going to copy-paste my answer from your other question.
I'd like to change the spacing inbetweem the rows of a JTextArea
My first thought was that overriding javax.swing.JTextArea#getRowHeight would be sufficient. The javadoc clearly states
Defines the meaning of the height of a row. This defaults to the height of the font.
So I was hoping that by overriding this method, you would adjust the definition and you would get more spacing between the rows. Bummer, didn't work. A quick search on the usages of that method in the JDK revealed the same. It is mainly used to calculate some sizes, but certainly not used when painting text inside the component.
By looking at the source code of the javax.swing.text.PlainView#paint method, I saw that the FontMetrics are used, and those you can easily override in the JTextArea. So second approach was to extend the JTextArea (bwah, extending Swing components but it is for a proof-of-concept)
private static class JTextAreaWithExtendedRowHeight extends JTextArea{
private JTextAreaWithExtendedRowHeight( int rows, int columns ) {
super( rows, columns );
}
#Override
public FontMetrics getFontMetrics( Font font ) {
FontMetrics fontMetrics = super.getFontMetrics( font );
return new FontMetricsWrapper( font, fontMetrics );
}
}
The FontMetricsWrapper class basically delegates everything, except the getHeight method. In that method I added 10 to the result of the delegate
#Override
public int getHeight() {
//use +10 to make the difference obvious
return delegate.getHeight() + 10;
}
And this results in more row spacing (and a caret which is way too long, but that can probably be adjusted).
A little screenshot to illustrate this (not as nice as some of the other ones, but it shows that this approach might work):
Small disclaimer: this feels like an ugly hack and might result in unexpected issues. I do hope somebody comes with a better solution.
I personally prefer the solution StanislavL is proposing, but this gives you an alternative
That's a piece of code. It's not finished. Line spacing between wrapped lines is not implemented. You can get full source of WrappedPlainView or PlainView and add your code there to achieve desired line spacing
import javax.swing.*;
import javax.swing.plaf.basic.BasicTextAreaUI;
import javax.swing.text.*;
public class LineSpacingTextArea {
public static void main(String[] args) {
JTextArea ta=new JTextArea();
JFrame fr=new JFrame("Custom line spacing in JTextArea");
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ta.setText("Line 1\nLine 2\nLong text to show how line spacing works");
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
ta.setUI(new CustomTextAreaUI());
fr.add(new JScrollPane(ta));
fr.setSize(100,200);
fr.setLocationRelativeTo(null);
fr.setVisible(true);
}
static class CustomTextAreaUI extends BasicTextAreaUI {
public View create(Element elem) {
Document doc = elem.getDocument();
Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
// build a view that support bidi
return super.create(elem);
} else {
JTextComponent c = getComponent();
if (c instanceof JTextArea) {
JTextArea area = (JTextArea) c;
View v;
if (area.getLineWrap()) {
v = new CustomWrappedPlainView(elem, area.getWrapStyleWord());
} else {
v = new PlainView(elem);
}
return v;
}
}
return null;
}
}
static class CustomWrappedPlainView extends WrappedPlainView {
public CustomWrappedPlainView(Element elem, boolean wordWrap) {
super(elem, wordWrap);
}
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
super.layoutMajorAxis(targetSpan, axis, offsets, spans);
int ls=spans[0];
for (int i=0; i<offsets.length; i++) {
offsets[i]+=i*ls;
}
}
}
}
I have tp place a AutoCompleteField in one of my screen in Blackberry app. I have to show a place holder text to provide hint for user to enter the information.
Here is the below code of AutoCompleteField
BasicFilteredList filterList = new BasicFilteredList();
String[] address = { "T 115 Centro Galleria Shopping Centre, Cnr Old Collier and Walters Road Morley WA 1522",
"1423 SEAVIEW POINT POINT COOK VIC 2674",
"Lot 1498 Yarraman Road Wyndham Vale VIC 3795",
"Lot 3506 Witchmount Close Hillside VIC 4055",
"6 Paas Place Williamstown VIC 4233",
"Lot 99 14 James Close Sunbury VIC 4502",
"1 Charlotte Street Clayton South VIC 4779" };
filterList.addDataSet(1, address, "address", BasicFilteredList.COMPARISON_IGNORE_CASE);
AutoCompleteField autoCompleteField = new AutoCompleteField(filterList){
public void onSelect(Object selection, int SELECT_TRACKWHEEL_CLICK) {
ListField _list = getListField();
if (_list.getSelectedIndex() > -1) {
if(selectedText!=null){
BasicFilteredListResult result = (BasicFilteredListResult) selection;
selectedText.setText(result._object.toString());
}
}
}
};
add(autoCompleteField);
Anyone, please suggest me how could I implement the same.
Thanks.
You can use a similar technique to the one shown here for normal EditFields. Basically, you need to override the paint() method in an AutoCompleteField subclass. In paint(), you check and see if the field is empty, and if so, you manually draw the placeholder text you want.
The difference is that AutoCompleteField is a Manager with a BasicEditField inside of it. So, to draw the text properly, you need to figure out the x and y offsets of the edit field within the parent Manager (the AutoCompleteField).
So, replace your AutoCompleteField instance with an instance of this class:
private class CustomAutoCompleteField extends AutoCompleteField {
private int yOffset = 0;
private int xOffset = 0;
public CustomAutoCompleteField(BasicFilteredList filteredList) {
super(filteredList);
}
protected void paint(Graphics g) {
super.paint(g);
if (xOffset == 0) {
// initialize text offsets once
xOffset = getEditField().getContentLeft();
yOffset = getEditField().getContentTop();
}
String text = getEditField().getText();
if (text == null || text.length() == 0) {
int oldColor = g.getColor();
g.setColor(Color.GRAY);
g.drawText("enter text", xOffset, yOffset);
g.setColor(oldColor);
}
}
public void onSelect(Object selection, int SELECT_TRACKWHEEL_CLICK) {
ListField _list = getListField();
if (_list.getSelectedIndex() > -1) {
if(selectedText!=null){
BasicFilteredListResult result = (BasicFilteredListResult) selection;
selectedText.setText(result._object.toString());
}
}
}
}
I tested this on OS 5.0, with an instance that didn't have any margin or padding set. It's possible that with different layouts, you may need to adjust the logic for calculating the x and y offsets. But, the above code shows you the basic idea. Good luck.
Edit: the above code is presented with the caveat that your onSelect() method is clearly relying on code not shown. As is, the above code won't compile. I left onSelect() in there just to show that I'm essentially just replacing the anonymous class you originally had, and not doing anything different in your onSelect() method, as it's not directly related to the placeholder text issue.
I'm trying to control some Java game from FireFox window. How can I send key and mouse events to that Java applet?
I'm using Windows XP if that matters.
Edit: I'm not trying to do this with Java even though i have the tag here. A c++ solution would be optimal.
You might try using Robot, but this might not work in FireFox. You can also use methods like abstractbutton.doClick()
If Robot doesn't work, key events you can synthesize by just setting text on a component, and mouse events you can use doClick() and requestFocus()
If none of that works, you might be able to accomplish your goals working with javascript and an html page.
Here is something that will work for keystrokes:
The recommended methods for both these actions are using SendInput
This website is perfect for beginning to understand sendinput
To find windows targets use Spy++, documentation
but I do have other examples below:
Example here is for Notepad using postmessage.
#include "TCHAR.h"
#include "Windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
HWND hwndWindowTarget;
HWND hwndWindowNotepad = FindWindow(NULL, L"Untitled - Notepad");
if (hwndWindowNotepad)
{
// Find the target Edit window within Notepad.
hwndWindowTarget = FindWindowEx(hwndWindowNotepad, NULL, L"Edit", NULL);
if (hwndWindowTarget) {
PostMessage(hwndWindowTarget, WM_CHAR, 'G', 0);
}
}
return 0;
}
You may also like to look at windows hooks, which can send mouse input
Or User32 mouse_event:
[DllImport("User32.Dll")]
private static extern void mouse_event(UInt32 dwFlags, int dx, int dy, UInt32 dwData, int dwExtraInfo);
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
public enum MouseEventFlags
{
LEFTDOWN = 0x00000002,
LEFTUP = 0x00000004,
MIDDLEDOWN = 0x00000020,
MIDDLEUP = 0x00000040,
MOVE = 0x00000001,
ABSOLUTE = 0x00008000,
RIGHTDOWN = 0x00000008,
RIGHTUP = 0x00000010
}
public static void SendLeftClick(int X, int Y)
{
mouse_event((uint)MouseEventFlags.LEFTDOWN, 0, 0, 0, 0);
mouse_event((uint)MouseEventFlags.LEFTUP, 0, 0, 0, 0);
}