我有一个JFrame
,其中包含JPanel
。 JPanel
中包含更多组件,例如JLabel
,JTextField
,JLabel
和JFileChooser
。
这些组件可以正确显示在应有的位置,但它们也应显示在窗口中(0, 0)
下方应有的位置。在上方显示的是最后一个关注的对象:
(Image) The JFileChooser is displayed as a separate window, but also displayed underneath what is supposed to be displayed at (0, 0)
如何防止这种情况发生?
代码:(省略了一些方法以使代码更短。这些与发布无关。)
package com.kasad.pathfinder.mapmaker.graphics.components
import com.kasad.pathfinder.mapmaker.grid.Node
import java.awt.Color
import java.awt.FlowLayout
import java.awt.Graphics
import java.awt.event.*
import javax.swing.JButton
import javax.swing.JFileChooser
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.filechooser.FileNameExtensionFilter
class DisplaySO : JPanel() {
companion object {
val WALKABLE_TILE_COLOR: Color = Color.WHITE
val WALL_TILE_COLOR: Color = Color.BLACK
val START_TILE_COLOR: Color = Color.GREEN
val END_TILE_COLOR: Color = Color.RED
val TILE_BORDER_COLOR: Color = Color.BLACK
const val GRID_MARGIN: Int = 50
}
private var nodes = arrayOf( // Start with a 3x3 grid of walkable nodes
... // Not relevant to issue (omitted)
)
// These variables (nodeSize, centerOffset[X/Y], grid[Height/Width]) are referred to as "draw sizes"
private var nodeSize = 0 // Size of each node
private var centerOffsetX = 0 // X offset to center grid
private var centerOffsetY = 0 // Y offset to center grid
private var gridWidth = 0 // The total width of the grid
private var gridHeight = 0 // The total height of the grid
private var previousWidth = 0 // Previous width of window
private var previousHeight = 0 // Previous height of window
private var startNode: Node? = null
private var endNode: Node? = null
private lateinit var prevMousedNode: Node // Previous node selected by mouse
private var currentKeyPressed: Char? = null
private var currentMouseButton: Int? = null
private val widthBox = JNumberField(6) // Create text boxes for grid width & height input
private val heightBox = JNumberField(6) // |
private val widthBoxLabel = JLabel("Rows:") // Text box labels
private val heightBoxLabel = JLabel("Columns:") // |
private val resizeButton = JButton("Resize") // Button to resize grid/process inputs
private val fileChooser = JFileChooser()
private val saveButton = JButton("Save to File")
fun init() {
isDoubleBuffered = true
isVisible = true
isFocusable = true
layout = FlowLayout(FlowLayout.LEFT)
add(widthBoxLabel)
add(widthBox)
add(heightBoxLabel)
add(heightBox)
add(resizeButton)
add(saveButton)
resizeButton.addActionListener {
this@DisplaySO.requestFocusInWindow()
val newWidth: Int
val newHeight: Int
try {
newWidth = widthBox.value
newHeight = heightBox.value
} catch (e: NumberFormatException) {
println("Error: Invalid number")
return@addActionListener
}
resizeGrid(newWidth, newHeight)
}
saveButton.addActionListener { // When the save button is pressed,
saveGrid() // Save the grid to a file
}
resizeButton.isFocusable = false // Set buttons as unfocusable (forces keystrokes to be processed by window)
saveButton.isFocusable = false // |
fileChooser.apply {
dialogTitle = "Choose file to save to..." // Window title
addChoosableFileFilter(FileNameExtensionFilter("Grid Map Files", "gmap")) // Add a file extension filter and
fileFilter = choosableFileFilters[1] // set it as the default
isMultiSelectionEnabled = false // Only allow selecting one file
}
addKeyListener(object : KeyListener {
override fun keyPressed(e: KeyEvent) {
if ((e.keyChar in 'A'..'Z' || e.keyChar in 'a'..'z') && currentKeyPressed != e.keyChar) {
currentKeyPressed = e.keyChar
println(e.keyChar)
}
}
override fun keyReleased(e: KeyEvent) {
if (currentKeyPressed == e.keyChar)
currentKeyPressed = null
}
override fun keyTyped(e: KeyEvent?) {}
})
addMouseListener(object : MouseListener {
override fun mousePressed(e: MouseEvent) {
if (!this@DisplaySO.isFocusOwner)
this@DisplaySO.requestFocusInWindow()
currentMouseButton = e.button
processMouseDown(e)
}
override fun mouseReleased(e: MouseEvent) {
if (currentMouseButton == e.button)
currentMouseButton = null
}
override fun mouseEntered(e: MouseEvent?) {}
override fun mouseExited(e: MouseEvent?) {}
override fun mouseClicked(e: MouseEvent?) {}
})
addMouseMotionListener(object : MouseMotionListener {
override fun mouseMoved(e: MouseEvent?) {}
override fun mouseDragged(e: MouseEvent) {
processMouseDown(e)
}
})
nodeSize = (height - 2 * GRID_MARGIN) / nodes.size
repaint()
}
private fun resizeGrid(newGridWidth: Int, newGridHeight: Int) {
... // Not relevant to issue (omitted)
}
private fun computeDrawSizes() {
... // Not relevant to issue (omitted)
}
private fun drawGrid(g: Graphics) {
var nodePositionX: Int
var nodePositionY: Int
for (row in nodes) {
for (node in row) {
nodePositionX = node.gridX * nodeSize + centerOffsetX
nodePositionY = node.gridY * nodeSize + centerOffsetY
with(g) {
color = when (true) {
node.walkable -> when {
node.isStartNode -> START_TILE_COLOR
node.isEndNode -> END_TILE_COLOR
else -> WALKABLE_TILE_COLOR
}
else -> WALL_TILE_COLOR
}
fillRect(
nodePositionX,
nodePositionY,
nodeSize,
nodeSize
)
color = TILE_BORDER_COLOR
drawRect(
nodePositionX,
nodePositionY,
nodeSize,
nodeSize
)
}
}
}
}
private fun processMouseDown(e: MouseEvent) {
... // Not relevant to issue (omitted)
}
private fun getNodeByPosition(x: Int, y: Int): Node? {
... // Not relevant to issue (omitted)
}
@Throws(IllegalArgumentException::class)
private fun updateNode(node: Node, newStatus: Int) {
... // Not relevant to issue (omitted)
}
private fun saveGrid() {
if (startNode == null || endNode == null) {
println("Error: must choose a start node and an end node")
return
}
if (fileChooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
return
fileChooser.selectedFile.writeText(
gridToString()
)
}
private fun gridToString(): String {
... // Not relevant to issue (omitted)
}
override fun paintComponent(g: Graphics) {
if (width != previousWidth || height != previousHeight) // If window has been resized,
computeDrawSizes() // recalculate the draw sizes
drawGrid(g) // Draw the grid
}
}
答案 0 :(得分:1)
对Kotlin一无所知,但我想问题是:
override fun paintComponent(g: Graphics) {
if (width != previousWidth || height != previousHeight)
在Swing中重写paintComponent(...)时的第一条语句应该是:
override fun paintComponent(g: Graphics) {
super.paintComponent(g); // added
if (width != previousWidth || height != previousHeight)
为确保清除背景,以确保没有绘画伪影。