I am creating a Video Player using VLCJ.
The player uses a Canvas as it's video surface.
videoPlayer.newVideoSurface(canvas);
So I am bounded to use Canvas.
I want to show message over the Canvas like, "Player Started". I tried using a JLayeredPane and a JLabel to accomplish this.
A short-demo code:
package canvasexample;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class CanvasExample extends JFrame
{
public JLabel label = new JLabel("Message");
public Canvas canvas = new MyCanvas();
public CanvasExample()
{
setSize(500, 500);
setLocationRelativeTo(null);
createWindow();
setVisible(true);
}
public void createWindow()
{
JLayeredPane pane = new JLayeredPane();
JPanel panel1 = new JPanel(new BorderLayout());
JPanel panel2 = new JPanel(new BorderLayout());
panel1.setSize(500, 500);
panel2.setSize(500, 500);
label.setBorder(new LineBorder(Color.BLUE));
panel1.add(canvas);
panel2.add(label, BorderLayout.NORTH);
pane.add(panel1, 1, 0);
pane.add(panel2, 2, 0);
add(pane);
}
private class MyCanvas extends Canvas
{
public MyCanvas() {
setBackground (Color.GRAY);
setSize(500, 500);
}
public void paint(Graphics g)
{
g.setColor(Color.red);
g.fillOval(75, 75, 150, 75);
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
new CanvasExample();
}
});
}
}
But soon I found out that you can't mix heavyweight AWT component and lightweight Swing components.
So, can anyone tell me how can I display a message over a Canvas?
If you are trying to overlay static text on an vlcj embedded canvas you need to use Marquess
Or use the marque options directly in the mediaplayer here
For overlays besides text you can have a look AbstractJWindowOverlayComponent
or I haven't tried this approach u can create an JLayeredPane where you have your canvas at layer 1 and can have your JComponent which will draw your overlays at layer 0 with transparent background you can override it's paintComponent() method and draw whatever you need
Related
I am currently working on a simple pong-like game, but I got stucked with positioning the rectangle.
I want to change it's Y position to be at the half of the actual panel's height.
package com.game;
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("gEngine");
Player playerOne = new Player(frame);
Player playerTwo = new Player(frame);
}
}
package com.game;
import javax.swing.*;
import java.awt.*;
public class Player {
public Player(JFrame frame) {
MyPanel panel = new MyPanel();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.BLACK);
frame.setSize(1280, 720);
frame.setVisible(true);
}
}
class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(50, 60, 20, 120);
}
}
Your code has a lot of "problems". I suggest you to find some kind of tutorials or something. You frame.setVisible(true) and stuff inside Player's class constructor. Do you realize that every time you create a Player object, all these things will be applied to the JFrame? Is this necessary? Maybe you should do them only once. Also in order to paint the compnent according to its position according size, you can do g.fillRect(50, getHeight() / 2, 20, 120);
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("gEngine");
Player playerOne = new Player();
Player playerTwo = new Player();
// Set the proper layout manager
frame.setLayout(new GridLayout());
frame.add(playerOne.getMyPanel());
frame.add(playerTwo.getMyPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.BLACK);
frame.setSize(1280, 720);
frame.setVisible(true);
}
public static class Player {
private JPanel myPanel;
public Player() {
this.myPanel = new MyPanel();
}
public JPanel getMyPanel() {
return myPanel;
}
}
static class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
// let the component be painted "natural"
super.paintComponent(g);
// Do custom painting
g.setColor(Color.WHITE);
g.fillRect(50, getHeight() / 2, 20, 120);
}
}
}
Edit (based on comment):
The background is the default one because GridLayout splits the screen into 2 panels (in the middle of the frame). Even the frame has BLACK background, these 2 panels cover it. So the background you see is from the panels, and not from the frame. In order to change it you will have to change the background of the panels (and make them non-transparent):
static class MyPanel extends JPanel {
public MyPanel() {
super();
setOpaque(true);
setBackground(Color.BLACK);
}
#Override
public void paintComponent(Graphics g) {
// let the component be painted "natural"
super.paintComponent(g);
// Do custom painting
g.setColor(Color.WHITE);
g.fillRect(50, getHeight() / 2, 20, 120);
}
}
I'm trying to draw a basic object to a JPanel
although it doesn't seem to be working.
I'm certain I am doing something wrong with where the paint method
is being called
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
public class testGui {
static colors gc_colors;
static gui gc_gui;
public static void main(String[] args) {
gc_colors = new colors();
gc_gui = new gui();
gc_gui.cv_frame.setVisible(true);
}
public static class colors {
Color cv_ltGrey;
Color cv_mdGrey;
Color cv_dkGrey;
public colors() {
cv_ltGrey = Color.decode("#DDDDDD");
cv_mdGrey = Color.decode("#CCCCCC");
cv_dkGrey = Color.decode("#111111");
}
}
public static class gui {
JFrame cv_frame;
JPanel cv_panel;
JPanel cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_panel = new JPanel();
cv_panel.setBackground(gc_colors.cv_ltGrey);
cv_panel.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_panel);
cv_content = new content();
cv_panel.add(cv_content);
}
}
public static class content extends JPanel {
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(gc_colors.cv_ltGrey);
graphic2D.fillRect(10, 10, 100, 100);
}
}
}
I have a class for my gui which I am adding a JPanel to (a light grey one).
Which I am then trying to add my drawing to using a JPanel extended class
called content.
When I run it though it seems to create the grey JPanel which I want but
the drawing is just a tiny white square and I'm not sure why.
So, you content panel has a default preferred size of 0x0, FlowLayout honours the preferredSize of its components (with a little margin), hence the reason why you have a nice little small white rectangle.
What you need to do is override the getPreferredSize method of the content panel and return a suitable size, for example
public static class content extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 120);
}
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(gc_colors.cv_ltGrey);
graphic2D.fillRect(10, 10, 100, 100);
}
}
I've decided to just leave out the second JPanel altogether.
It was too much of a hassle to put the JPanel inside of another JPanel
so instead I am only going to use a single JPanel
public static class gui {
JFrame cv_frame;
JPanel cv_panel;
JPanel cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_content = new content();
cv_content.setBackground(gc_colors.cv_ltGrey);
cv_content.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_content);
}
}
This what I am doing but is nothing is getting displayed on Jframe window. I have not extended class JFrame to do my, is it necessary to do so for displaying objects on window.
public class testGraphics {
static JFrame workingFrame = null;
public static void main(String args[])
{
JFrame workingManager = new JFrame("Hello");
workingManager.setSize(500, 500);
workingManager.setVisible(true);
Graphics g = workingManager.getGraphics();
JPanel jp = (JPanel) workingManager.getContentPane();
workingManager.paintComponents(g);
g.fillOval(0, 0, 30, 30);
g.drawOval(0, 50, 30, 30);
g.setColor(Color.CYAN);
}
}
Do not ever call getGraphics() or explicitly call paintXxx() to do custom painting. The correct way to do custom painting is to override the paintComponent method of the panel to paint on. The overriden method will be implicitly called for you. Then add that panel to the frame. Also you should override the getPreferredSize() of the panel, so it has a preferred size, so you can just pack the frame
class PaintPanel extends JPanel {
#Override
protected paintComponent(Grapchics g) {
super.paintComponent(g);
g.drawString(....);
}
#Override
public Dimension getPreferredSize() {'
return new Dimension(300, 300);
}
}
Then add it to the frame (or if you want to set it as the content pane of the frame, do that instead)
PaintPanel panel = new PaintPaint();
frame.add(panel);
...
frame.pack();
See more at Performing Custom Painting
I made several changes to your code to get it to work properly.
I changed your main method to call the SwingUtilities invokeLater method to make sure that the Swing components were defined and used on the Event Dispatch thread.
I created a drawing JPanel. I set the color first, then drew the ovals.
I added a JFrame default close operation. You must specify a default close operation, or else your Java application will continue running after you close the JFrame.
I moved the size to the drawing panel. The frame size will be calculated when you call the JFrame pack method.
And here's the modified code:
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestGraphics implements Runnable{
private JFrame workingManager;
private JPanel drawingPanel;
#Override
public void run() {
workingManager = new JFrame("Hello");
workingManager.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel();
workingManager.add(drawingPanel, BorderLayout.CENTER);
workingManager.pack();
workingManager.setLocationByPlatform(true);
workingManager.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new TestGraphics());
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID =
-3701718376300985046L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(500, 500));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.CYAN);
g.fillOval(0, 0, 30, 30);
g.drawOval(0, 50, 30, 30);
}
}
}
The setSize() and setVisible() must be at the bottom of the method:
JFrame workingManager = new JFrame("Hello");
Graphics g = workingManager.getGraphics();
JPanel jp = (JPanel) workingManager.getContentPane();
workingManager.paintComponents(g);
g.fillOval(0, 0, 30, 30);
g.drawOval(0, 50, 30, 30);
g.setColor(Color.CYAN);
workingManager.setSize(500, 500);
workingManager.setVisible(true);
I'm trying to display a message in a JPanel.
I've used the drawString() function of the Graphics class.
Here's my code :
public class Frame {
JFrame frame;
JPanel panel;
Graphics graph;
Frame() {
frame = new JFrame();
panel = new JPanel();
frame.setTitle("My wonderful window");
frame.setSize(800, 600);
frame.ContentPane(panel);
frame.setVisible(true);
}
void displayMessage(String message) {
graph = new Graphics();
graph.drawString(message, 10, 20);
}
}
I've this error :
error: Graphics is abstract; cannot be instantiated
Override the JPanel's paintComponent(Graphics g) method. IN the method you have access to a valid Graphics instance. The method called on each paint.
But may be it's better to add a JLabel to the panel. The label initially has no text and when you have a message just call setText(messageText) of the label.
You should create subclasses for your JFrame and JPanel, and override the methods you want. You could try something like:
package test;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame {
public static final String message = "HELLO WORLD!!!";
public class Panel extends JPanel {
public void paintComponent(Graphics graph) {
graph.drawString(message, 10, 20);
}
}
public Frame() {
Panel panel = new Panel();
this.setTitle("My wonderful window");
this.setSize(800, 600);
this.setContentPane(panel);
this.setVisible(true);
}
public static void main(String[] args) {
new Frame();
}
}
Also, there are a lot of great books/tutorials about this. You should read one.
Edit:
You should also read about all the JComponents (JButtons, JLabels...). They're rather useful.
I have this GUI class:
import java.awt.*;
import javax.swing.*;
public class Exp2 extends JFrame {
public Exp2 () {
setLayout(new FlowLayout());
setSize(360, 360);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
add(panel2);
add(panel1);
panel1.paint(null);
JButton button1 = new JButton("Run");
panel2.add(button1, BorderLayout.PAGE_END);
}
public void paint(Graphics g) {
g.setColor(Color.green);
g.fillRect(50, 50, 20, 20);
}
}
along with this main class:
import javax.swing.JFrame;
class Exp1 extends JFrame {
public static void main(String[] args) {
Exp2 box = new Exp2();
}
}
But the JButton button1 only appears after I roll my mouse over where it should be. What am I doing wrong?
You never call
super.paint(g);
which paints the containers child components.
Don't do custom painting in a top level container such as JFrame. Rather move the paint functionality to a subclass of JComponent. There override paintComponent rather than paint and invoke super.paintComponent(g). This takes advantage of the improved performance of Swing double buffering mechanism.
See: Performing Custom Painting
Call a repaint on the JFrame after you've added everything. Additionally, you need to call super.paint(g) from your paint method.