Below code is my view where I get display a streaming camera. Controller handles sets the image and repaints the JInternalFrame. I have an issue with this because the camera image covers the whole JInternalFrame even the title bar. I tried using JPanel but I had problems getting the image on the JPanel because I extend JInternalFrame.
public class CameraView extends JInternalFrame{
private BufferedImage image;
public CameraView(){
super("Camera", false,false,false, false);
setSize(500,500);
setLocation(200,200);
}
#Override
public void paint(Graphics g){
g.drawImage(image, 0, 0, null);
}
public void setImage(BufferedImage image){
this.image = image;
}
}
This is what it looks like. No title bar.
You're overriding the paint method of the frame. This paint method is what draws the title bar.
You should create a second class that extends JComponent, override the paint method on that class, and then add an instance of it to your frame.
Something like:
public class CameraView extends JInternalFrame{
private BufferedImage image;
public CameraView(){
super("Camera", false,false,false, false);
setLocation(200,200);
add(new JComponent() {
{
setSize(500, 500); // size of the image
}
#Override
public void paint(Graphics g){
g.drawImage(image, 0, 0, null);
}
});
pack();
}
public void setImage(BufferedImage image){
this.image = image;
}
}
You could also have the paint method call super.paint(g); but the way you have it set up now, your image will overlay the title bar.
Also, calling super("Camera", false,false,false, false); is the same as calling super("Camera"). The defaults are false.
Related
I am trying to add an Icon to the JButton
When I try to do this my Layout Manager (I use GridBagLayout) resizes the button and makes it larger by the size of the icon.
Is there a way to avoid this?
You could try JButton#setPreferedSize(...)
Or you could override the paintComponent method:
JButton testButton = new JButton() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
If you want to do this with multiple buttons, it would be better to make a class for it ofcourse, something like:
class ImageButton extends JButton {
private final Image image;
public ImageButton(Image image) {
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//drawing logic here
}
}
I had the same problem. Do these things:
Resize your image to fit the button with an image manipulating program.
use setMininumSize() and set the minimum size you want.
This will probably fix your problem.
Let's say we have a JTextPane and its size is set to A4 paper format size. Orientation of the page is vertical. Let's divide our page into three equal parts. When I write something in one part (in random place) I want that inserted text would be drawn on two remaining parts of the page in such a place that if I fold my page on three, all three texts will be in the same place.
Is ther any way to achieve this?
This should look like this:
I'm not sure I understood what you want, so please correct me if I misunderstood. You can save the image of your textPane when displayed, and draw that image reverted or normally as needed. See below:
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);
//layout to make every part the same size
Container pane = mainFrame.getContentPane();
pane.setLayout(new GridLayout(3,1));
//create the elements
JTextPane source = new Source();
final JPanel copy = new Copy();
final JPanel revertedCopy = new RevertedCopy();
//add the elements
pane.add(source);
pane.add(revertedCopy);
pane.add(copy);
//This is just to display the splitting lines
source.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.BLACK));
//this is just to repaint the other panels when image changes
source.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals("drawing")) {
copy.repaint();
revertedCopy.repaint();
}
}
});
mainFrame.setVisible(true);
}
});
}
static BufferedImage image;
static class Source extends JTextPane {
#Override
public void paint(Graphics g) {
super.paint(g);
//we edit the image each time the textPane is repainted
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
boolean caretVisible = getCaret().isVisible(), selectionVisible = getCaret().isSelectionVisible();
if(caretVisible) getCaret().setVisible(false);
if(selectionVisible) getCaret().setSelectionVisible(false);
super.paint(image.createGraphics());
if(caretVisible) getCaret().setVisible(true);
if(selectionVisible) getCaret().setSelectionVisible(true);
//we let the copies know about the changes
firePropertyChange("drawing", null, image);
}
}
static class Copy extends JPanel {
#Override
public void paint(Graphics g) {
super.paint(g);
//we just draw the image
if(image!=null) g.drawImage(image, 0, 0, this);
}
}
static class RevertedCopy extends JPanel {
#Override
public void paint(Graphics g) {
super.paint(g);
//we just draw the image reverted
if(image!=null) g.drawImage(image, 0, image.getHeight(), image.getWidth(), -image.getHeight(), this);
}
}
}
A DocumentListener is needed . On changeEvent the text should be copied (till the caret position) and appened adjusting line gaps (for overflow of text). CaretPositionshould be keep into the original position. What happens when text overflows the first part should be taken care of.
You should replace root view with your own one. View has method
public void paint(Graphics g, Shape allocation)
You override the method and call super.paint(g, allocation) 3 times translating Graphics vertically.
Also you should override getPreferredSpan() to triple original vertical span.
I'm trying to make a screenshot tool that shows screenshot picture to user in fullscreen. Then user will edit it with a few tools.
While creating it, i faced a problem with visualization of some effects.
I want to create visual representation of selected area using selection rectangle(don't know the exact term name) that you use to select multiple files on desktop or file explorer. example image link
I tried to do it with drawing rectangle on background picture, but when i tried to move a cursor, image was refreshing ugly.
Then I tried to do transparent panel with both setOpaque(false); and setBackground(new Color(0,0,0,0)); and than pin mouse listeners on this panel.
It draws rectangle successfully, but background of panel instantly fills with default grey color.
How can i make foreground panel transparent and draw something on it, without repainting background image?
Here is my Glass class:
private static final int WIDE = 1920;
private static final int HIGH = 1080;
private final Color clean = new Color(0,0,0,0);
private Point mousePt = new Point(WIDE / 2, HIGH / 2);
private Rectangle mouseRect = new Rectangle();
Glass(){
this.setOpaque(false);
this.setBackground(clean);
this.addMouseListener(new MouseHandler());
this.addMouseMotionListener(new MouseMotionHandler());
}
public void paintComponent(Graphics g) {
g.setColor(clean);
g.fillRect(0, 0, 1920, 1080 );
g.setColor(Color.darkGray);
g.drawRect(mouseRect.x, mouseRect.y, mouseRect.width, mouseRect.height);
}
private class MouseHandler extends MouseAdapter {
public void mouseReleased(MouseEvent e) {
System.out.println("released");
mouseRect.setBounds(0, 0, 0, 0);
e.getComponent().repaint();
}
public void mousePressed(MouseEvent e) {
mousePt = e.getPoint();
System.out.println("pressed");
e.getComponent().repaint();
}
}
private class MouseMotionHandler extends MouseMotionAdapter {
public void mouseDragged(MouseEvent e){
mouseRect.setBounds(
Math.min(mousePt.x, e.getX()),
Math.min(mousePt.y, e.getY()),
Math.abs(mousePt.x - e.getX()),
Math.abs(mousePt.y - e.getY()));
e.getComponent().repaint();
}
}
Have you already tried adding super.paintComponent(g) to the beginning of your paintComponent method like so:
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(clean);
g.fillRect(0, 0, 1920, 1080 );
g.setColor(Color.darkGray);
g.drawRect(mouseRect.x, mouseRect.y, mouseRect.width, mouseRect.height);
}
Another possibility would be to use a JPanel for all of your drawing and just draw the background image in your paintComponent method too:
class DrawPanel extends JPanel{
public DrawPanel(){
//...
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//Draw background
g.drawImage(yourImage, 0, 0);
//Your drawing
g.setColor(Color.darkGray);
g.drawRect(mouseRect.x, mouseRect.y, mouseRect.width, mouseRect.height);
}
}
Using a JPanel instead of a java.awt.Panel will use double-buffering and avoid any flickering while drawing.
Your code of the parent-container could look like:
public MainFrame(){
//...
//Your old code
//background image...
//getContentPane().add(glass);
getContentPane().add(drawPanel);
}
MASSIVE EDIT: I added more descritpion and code.
I recently encounter a problem where a panel that I added to another panel won't display properly (only display a black dot instead of the image). The flow of the code is: the Menu class has a button panel. When the button start is press, the Menu remove the button panel, create a Board object(that implement panel) and add it to Menu. In Board constructor, an image is loaded (a .png), then a PlayerPanel (that implement panel) is added to the board panel. In PlayerPanl constructor, an image is loaded.
The plan is to make the menu repaint() method able to call Board paintcomponent. Board will then ask PlayerPanel to paintComponent. PlayerPanel paint his image, Board paint his image and that's it, both image should display.
public class Menu extends JFrame implements ActionListener
{
Board theBoard;
JPanel pnlButton = new JPanel();
JButton btnStart = new Jbutton("Start");
public Menu(String s)
{
pnlButton.add(btnStart);
super.add(pnlButton);
super.setLocation(0,0);
super.setSize(600, 500);
super.setResizable(false);
super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void actionPerformed(ActionEvent evt)
{
if(evt.getSource() == btnStart)
{
theBoard = new Board ("TestBoard");
super.remove(pnlButton);
super.add(theBoard);
super.repaint();
}
}
}
public class Board extends JPanel
{
BufferedImage boardImage;
PlayerPanel playerPanel;
public Board (String boardName)
{
boardImage = Tools.loadImage(boardName);
playerPanel = new PlayerPanel();
this.add(playerPanel);
}
#Override
public void paintComponent(Graphics g)
{
g.drawImage(boardImage, 0, 200, null);
}
}
public class PlayerPanel extends JPanel
{
BufferedImage playerImage;
public PlayerPanel()
{
playerImage = Tools.loadImage("TestPlayer");
}
#Override
public void paintComponent(Graphics g)
{
g.drawImage(playerImage, 0, 0, null);
}
}
Both image load successfully as tested, but when the repaint() is call from the JFrame holding the Board panel, only the image in Board is painted, and the image in PlayerPanel is replace with a black dot.
Any help? Thanks!
Your problem seems to be due to the size of your PlayerPanel JPanel. Sometimes it helps to debug things by testing to see what size things are when they're rendered. For instance, if you change your Board paintComponent method to this:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (boardImage != null) {
g.drawImage(boardImage, 0, 200, null);
}
System.out.printf("Board size: [%d, %d]%n", getWidth(), getHeight());
System.out.printf("Player size: [%d, %d]%n", playerPanel.getWidth(), playerPanel.getHeight());
}
it will tell you exactly what the sizes are of itself and its constituent playerPanel.
To solve the issue, you could give Board a layout manager that expands its constituent components such as a BorderLayout. Another possible solution is to give PlayerPanel its own getPreferredSize() method override, especially if you want it to size itself to its image. e.g.,
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (playerImage != null) {
g.drawImage(playerImage, 0, 0, null);
}
}
Alternatively, you could use a JLabel that holds an ImageIcon rather than draw in the JPanel.
Note, you should swap views with a CardLayout rather than calling remove(...), add(...), revalidate(), repaint()
I've been working on a drinking game program for school.
//this is the game //http://sotallytober.com/games/verbal/mexican/
Anyway, I painted a image in an JPanel using the following code (it's an class that extends JPanel)
public class iconPanel extends JPanel {
ImageIcon image;
Image pic;
public iconPanel(String startScreenImage) {
image = new ImageIcon(startScreenImage);
pic = image.getImage();
this.setBackground(new Color(0, true));
}
#Override
public void paintComponent(Graphics g) {
//Paint background first
g.drawImage (pic, 0, 0, getWidth (), getHeight (), this);
}
Now in my other class, where I have the layout and all the components I declare on top my JPanels like this :
private JPanel pnDrinkPlayerBW;
Then in a method in the same class named MakeComponents I set the JPanel to :
pnDrinkPlayerBW = new iconPanel("img/glass.jpg");
pnDrinkPlayerBW.setPreferredSize(new Dimension(183,61));
Afterwards I add it to the Panel where it has to come, and that panel onto the frame in the method makeLayout() (I don't think that it's useful code, so if you want to see it, ask me)
Then if a button gets pressed, I want to change the glass.jpg image to another image, for example beerGlass0.png, so in the actionlistener in another method actionEvents() I do this:
pnDrinkPlayerBW = new iconPanel("img/beerGlass.png");
pnDrinkPlayerBW.setPreferredSize(new Dimension(183,61));
pnDrinkPlayerBW.repaint();
I'll put the constructor of this class also here, just if people need it :
public SpelScreen(){
makeComponents();
makeLayout();
actionEvents();
} // note : this is'nt the full constructor, just the call for the methods I talked about, SpelScreen extends JFrame..
So what I want to do, is to set in the class SpelScreen a new image for the iconPanel and repaint it using the same instance of the spelscreen.
I am quite new to Java, so don't expect me to rapidly understand complicated code :)
Thanks!
First off you're forgetting to call super.paintComponent in your paintComponent method. Also paintComponent should be protected not public
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(..);
}
Second, I don't think you want to create a new iconPanel and immediately call repaint on it. That will probably do nothing.
Instead have a setter for your pic, then just repaint(); inside that method.
public void setPic(Image pic) {
this.pic = pic;
repaint();
}
Then you can just call the setPic from the the class you created the iconPanel in. For example
iconPanel panel = new iconPanel("...");
... // then in some listener
public void actionPerformed(ActionEvent e) {
Image pic = null;
try {
pic = ImageIO.read(...);
panel.setPic(pic);
} catch ...
}
Another option is just to have an array of images you initialize in the iconPanel. Then in a a listener, you can just change the index the if the image array then call repaint. Something like this
Image[] images = new Image[5];
int imageIndex = 0;
// fill the array with images
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images[imageIndex], ...);
}
Then you could just change the imageIndex and repaint()
Side Note
You should be using Java naming convention. Class names being with capital letters i.e. iconPanel → IconPanel
Update
Using ImageIcon
public void setImage(ImageIcon img) {
pic = img.getImage();
repaint();
}