Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Java output to a MS-DOS style screen

0 views
Skip to first unread message

Chris Smith

unread,
Aug 12, 2002, 1:18:38 PM8/12/02
to
[Followup-To set]

Chris Smith (that's me!) wrote ...
> Hmm... I'll see about throwing an example together... but it'd be
> multiple classes for the true model/view approach, and a little too long
> to post. Your email doesn't appear to be valid.

Here's a shot. In doing this, I realized how little I know about some of
the Swing mechanisms. For example, the component here doesn't respect a
border if you set one, so it draws off the sides, and it doesn't preserve
a preferred size set via the setPreferredSize method. Can someone tell
me if there's a standard way to modify this code to do such things? What
else is missing here?

Here goes...

=== CharCell.java

package net.twu.cdsmith.charcell;

import java.awt.*;
import javax.swing.*;

public class CharCell extends JComponent
{
private CharCellModel model;
private CharCellListener listener = new CharCellListener()
{
public void cellsAdded(CharCellEvent event)
{
revalidate();
repaint();
}

public void cellsRemoved(CharCellEvent event)
{
revalidate();
repaint();
}

public void cellsChanged(CharCellEvent event)
{
repaint();
}
};

private Font font;

public CharCell()
{
this(new DefaultCharCellModel(10, 10));
}

public CharCell(CharCellModel model)
{
setModel(model);
font = new Font("Monospaced", Font.PLAIN, 12);
}

public void setModel(CharCellModel model)
{
CharCellModel oldModel = this.model;
if (oldModel != null)
oldModel.removeCharCellListener(listener);

this.model = model;
model.addCharCellListener(listener);
}

public CharCellModel getModel()
{
return model;
}

public Dimension getPreferredSize()
{
FontMetrics metrics = getFontMetrics(font);
int cellWidth = metrics.charWidth('W');
int cellHeight = metrics.getHeight();

int width = model.getColumns() * cellWidth;
int height = model.getRows() * cellHeight;

return new Dimension(width, height);
}

public Dimension getMinimumSize()
{
return getPreferredSize();
}

public void paintComponent(Graphics g)
{
int cellWidth = getWidth() / model.getColumns();
int cellHeight = getHeight() / model.getRows();

g.setFont(font);

for (int row = 0; row < model.getRows(); row++)
{
for (int col = 0; col < model.getColumns(); col++)
{
int startx = col * cellWidth;
int starty = (row + 1) * cellHeight;

String text =
String.valueOf(model.getCharacter(row, col));

g.setColor(model.getColor(row, col));
g.drawString(text, startx, starty);
}
}
}
}

=== CharCellModel.java

package net.twu.cdsmith.charcell;

public interface CharCellModel
{
public int getRows();
public int getColumns();

public char getCharacter(int row, int col);
public java.awt.Color getColor(int row, int col);

public void addCharCellListener(CharCellListener listener);
public void removeCharCellListener(CharCellListener listener);
}

=== CharCellListener.java

package net.twu.cdsmith.charcell;

public interface CharCellListener extends java.util.EventListener
{
public void cellsChanged(CharCellEvent event);
public void cellsAdded(CharCellEvent event);
public void cellsRemoved(CharCellEvent event);
}

=== CharCellEvent.java

package net.twu.cdsmith.charcell;

public final class CharCellEvent extends java.util.EventObject
{
private final int startRow;
private final int endRow;
private final int startCol;
private final int endCol;

public CharCellEvent(Object source, int srow, int scol, int erow,
int ecol)
{
super(source);

this.startRow = srow;
this.endRow = erow;
this.startCol = scol;
this.endCol = ecol;
}

public int getStartRow()
{
return startRow;
}

public int getStartCol()
{
return startCol;
}

public int getEndRow()
{
return endRow;
}

public int getEndCol()
{
return endCol;
}
}

=== AbstractCharCellModel.java

package net.twu.cdsmith.charcell;

import javax.swing.event.EventListenerList;

public abstract class AbstractCharCellModel implements CharCellModel
{
private EventListenerList listenerList = new EventListenerList();

public void addCharCellListener(CharCellListener listener)
{
listenerList.add(CharCellListener.class, listener);
}

public void removeCharCellListener(CharCellListener listener)
{
listenerList.remove(CharCellListener.class, listener);
}

protected void fireCellsChanged(int srow, int scol, int erow, int
ecol)
{
CharCellEvent event = new CharCellEvent(this, srow, scol,
erow, ecol);
Object[] listeners =
listenerList.getListeners(CharCellListener.class);

for (int i = 0; i < listeners.length; i++)
{
CharCellListener listener = (CharCellListener)
listeners[i];
listener.cellsChanged(event);
}
}

protected void fireCellsAdded(int srow, int scol, int erow, int
ecol)
{
CharCellEvent event = new CharCellEvent(this, srow, scol,
erow, ecol);
Object[] listeners =
listenerList.getListeners(CharCellListener.class);

for (int i = 0; i < listeners.length; i++)
{
CharCellListener listener = (CharCellListener)
listeners[i];
listener.cellsAdded(event);
}
}

protected void fireCellsRemoved(int srow, int scol, int erow, int
ecol)
{
CharCellEvent event = new CharCellEvent(this, srow, scol,
erow, ecol);
Object[] listeners =
listenerList.getListeners(CharCellListener.class);

for (int i = 0; i < listeners.length; i++)
{
CharCellListener listener = (CharCellListener)
listeners[i];
listener.cellsRemoved(event);
}
}
}

=== DefaultCharCellModel.java

package net.twu.cdsmith.charcell;

import java.awt.Color;

public class DefaultCharCellModel extends AbstractCharCellModel
{
private char[][] characters;
private Color[][] colors;

public DefaultCharCellModel(int rows, int cols)
{
characters = new char[rows][cols];
colors = new Color[rows][cols];

for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
characters[row][col] = ' ';
colors[row][col] = Color.BLACK;
}
}
}

public int getRows()
{
return characters.length;
}

public int getColumns()
{
return (characters.length > 0) ? characters[0].length : 0;
}

public char getCharacter(int row,int col)
{
return characters[row][col];
}

public java.awt.Color getColor(int row,int col)
{
return colors[row][col];
}

public void setCharacter(int row, int col, char c)
{
characters[row][col] = c;
fireCellsChanged(row, col, row, col);
}

public void setColor(int row, int col, Color c)
{
colors[row][col] = c;
fireCellsChanged(row, col, row, col);
}

public void setCell(int row, int col, char ch, Color color)
{
characters[row][col] = ch;
colors[row][col] = color;
fireCellsChanged(row, col, row, col);
}
}

Any ideas?

Thanks,
Chris Smith

Jim Sculley

unread,
Aug 12, 2002, 8:34:12 PM8/12/02
to
Chris Smith wrote:
> [Followup-To set]
>
> Chris Smith (that's me!) wrote ...
>
>>Hmm... I'll see about throwing an example together... but it'd be
>>multiple classes for the true model/view approach, and a little too long
>>to post. Your email doesn't appear to be valid.
>
>
> Here's a shot. In doing this, I realized how little I know about some of
> the Swing mechanisms. For example, the component here doesn't respect a
> border if you set one, so it draws off the sides, and it doesn't preserve
> a preferred size set via the setPreferredSize method. Can someone tell
> me if there's a standard way to modify this code to do such things?

A call to paint() by the system does the painting in the following order:

paintComponent();
paintBorder();
paintChildren();

Your paintComponent() code has to take the border insets into consideration,
because JComponent will nto do it automatically. You can call getInsets() along
with getWidth() and getHeight() to determine the true area available for
painting. When getInsets() is called on a JComponent, the call is delegated to
the Border itself (provided that the border isn't 'null').

Jim S.


Chris Smith

unread,
Aug 12, 2002, 10:39:35 PM8/12/02
to
Jim Sculley wrote ...

> Your paintComponent() code has to take the border insets into consideration,
> because JComponent will nto do it automatically. You can call getInsets() along
> with getWidth() and getHeight() to determine the true area available for
> painting. When getInsets() is called on a JComponent, the call is delegated to
> the Border itself (provided that the border isn't 'null').

Okay, cool... done.

Now, anyone want to help out with background color and opacity? Is that
up to the implementation to decide, or is there some kind of built-in
support to make it work in JComponent? It's not working now... I can
call setBackground(Color.BLACK) and setOpaque(true), and the border's
background color changes, but the background color of the component is
the same unless I fillRect from paintComponent.

Chris Smith

Linda Radecke

unread,
Aug 13, 2002, 3:21:28 AM8/13/02
to
Chris Smith wrote:

> Jim Sculley wrote ...
[...]
> Okay, cool... done.

> Now, anyone want to help out with background color and opacity? Is that
> up to the implementation to decide, or is there some kind of built-in
> support to make it work in JComponent? It's not working now... I can
> call setBackground(Color.BLACK) and setOpaque(true), and the border's
> background color changes, but the background color of the component is
> the same unless I fillRect from paintComponent.

JComponent itself doesn't set up a custom UI-delegate, only it's
subclasses, such as JPanel, do. Therefore it doesn't paint it's
background even if set to opaque, you will always have to paint
it yourself as you do via fillRect here. There is an article at
Sun which explains it more detailed and Christian Kaufhold has
one with respect to opacity in general on his WebSite.

Hope this helps

Linda
--
(=) li...@jalice.ch - http://www.jalice.net
/
(=) l.ra...@hswzfh.ch - http://www.hswzfh.ch

Christian Kaufhold

unread,
Aug 13, 2002, 8:23:08 AM8/13/02
to
Hello!

Chris Smith <cds...@twu.net> wrote:

> Okay, cool... done.

1. JComponent itself never paints anything. For components with an XXXUI,
the UI will paint, but JComponent has none. So you have to paint it on
your own.


2. http://www.chka.de/swing/components/opacity.html

Fixing this chaos can be done for custom components easily. A
simple solution is:


import javax.swing.JComponent;

import java.awt.Transparency;
import java.awt.Color;

import java.awt.Graphics;


public abstract class FComponent
extends JComponent
{
private boolean backgroundPainted;


public final boolean isBackgroundPainted()
{
return backgroundPainted;
}

public void setBackgroundPainted(boolean value)
{
if (backgroundPainted == value)
return;

boolean oldOpaque = isOpaque();

backgroundPainted = value;

handleOpaque(oldOpaque);

repaint();

firePropertyChange("backgroundPainted", !backgroundPainted, backgroundPainted);
}

public void setBackground(Color value)
{
boolean oldOpaque = isOpaque();

super.setBackground(value);

handleOpaque(oldOpaque);
}

private void handleOpaque(boolean oldOpaque)
{
if (oldOpaque != isOpaque())
firePropertyChange("opaque", oldOpaque, !oldOpaque);
}

/** Do not use. Broken, may have no effect. */
public void setOpaque(boolean value)
{
}

public final boolean isOpaque()
{
return isBackgroundPainted() && getBackground() != null && getBackground().getTransparency() == Transparency.OPAQUE;
}

protected void paintComponent(Graphics g)
{
if (isBackgroundPainted() && getBackground() != null)
{
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}

paintComponentImpl(g);
}

protected abstract void paintComponentImpl(Graphics g);
}

This can be augmented to paint the background only if needed (i.e.
if painting and border are completely opaque, it isn't.) I remember
posting something like that.


Christian

Jim Sculley

unread,
Aug 13, 2002, 8:06:25 AM8/13/02
to
Chris Smith wrote:
> Jim Sculley wrote ...
>
>>Your paintComponent() code has to take the border insets into consideration,
>>because JComponent will nto do it automatically. You can call getInsets() along
>>with getWidth() and getHeight() to determine the true area available for
>>painting. When getInsets() is called on a JComponent, the call is delegated to
>>the Border itself (provided that the border isn't 'null').
>
>
> Okay, cool... done.
>
> Now, anyone want to help out with background color and opacity? Is that
> up to the implementation to decide, or is there some kind of built-in
> support to make it work in JComponent?

If you look at the online docs for JComponent in JDK 1.4.x you'll find
an expanded description of your responsibilities when overriding
paintComponent(). My local copy of the docs doesn't include the
following text. Perhaps yours doesn't either.

=====================
* If you override this in a subclass you should not make permanent
* changes to the passed in <code>Graphics</code>. For example, you
* should not alter the clip <code>Rectangle</code> or modify the
* transform. If you need to do these operations you may find it
* easier to create a new <code>Graphics</code> from the passed in
* <code>Graphics</code> and manipulate it. Further, if you do not
* invoker super's implementation you must honor the opaque
* property, that is if this component is opaque, you must
* completely fill in the background in a non-opaque color. If you
* do not honor the opaque property you will likely see visual
* artifacts.
=====================

Jim S.

0 new messages