Vinnaren i pepparkakshustävlingen!
2016-01-31, 18:26
  #1
Medlem
binics avatar
Jag har stött på ett konstigt problem när jag försöker ändra data i en DocumentFilter subklass. Jag försöker ändra en räknare när metoden remove anropas. De ärvda metoderna remove, replace och insert fungerar annars som de ska.

Kod:
public class Test() {
    
JTextPane pane = new JTextPane();
    
int counter 0;

    
CustomerFilter customerFilter = new CustomerFilter(panecounter);
    ((
AbstractDocument)(pane.getDocument())).setDocumentFilter(customerFilter);

    
customerFilter.incCounter(10);


Kod:
public class CustomFilter extends DocumentFilter {
    private 
JTextPane pane;
    private 
int counter;

public 
CustomFilter(JTextPane paneint counter) {
    
this.pane pane;
    
this.counter counter;
}
public 
void remove(FilterBypass fbint offsetint lengththrows BadLocationException {
    
super.remove(fboffsetlength);
    
System.out.println("Counter: " counter); //denna är alltid 0!?
}
...
public 
void incCounter(int newCounter) {
    
counter newCounter;    

I exemplet ovan så är countern alltid 0. Vad har jag missat?
Citera
2016-01-31, 18:43
  #2
Medlem
binics avatar
För att förtydliga min fråga så undrar jag varför remove/replace/insert metoderna inte får rätt värde på räknaren när jag får det från de andra metoderna jag skapat? Jag kan tex få ut rätt värde via incCounter metoden:

Kod:
public void incCounter(int newCounter) { 
    
counter newCounter;
    
System.out.println("Counter is now: " counter); //här skrivs rätt värde ut

Citera
2016-01-31, 19:13
  #3
Moderator
Protons avatar
Citat:
Ursprungligen postat av binic
Jag har stött på ett konstigt problem när jag försöker ändra data i en DocumentFilter subklass. Jag försöker ändra en räknare när metoden remove anropas. De ärvda metoderna remove, replace och insert fungerar annars som de ska.

Kod:
public class Test() {
    
JTextPane pane = new JTextPane();
    
int counter 0;

    
CustomerFilter customerFilter = new CustomerFilter(panecounter);
    ((
AbstractDocument)(pane.getDocument())).setDocumentFilter(customerFilter);

    
customerFilter.incCounter(10);


Kod:
public class CustomFilter extends DocumentFilter {
    private 
JTextPane pane;
    private 
int counter;

public 
CustomFilter(JTextPane paneint counter) {
    
this.pane pane;
    
this.counter counter;
}
public 
void remove(FilterBypass fbint offsetint lengththrows BadLocationException {
    
super.remove(fboffsetlength);
    
System.out.println("Counter: " counter); //denna är alltid 0!?
}
...
public 
void incCounter(int newCounter) {
    
counter newCounter;    

I exemplet ovan så är countern alltid 0. Vad har jag missat?
variabeln counter ser ju aldrig ut att ändras förutom i metoden incCounter, hur skulle den kunna anta något annat värde i exempelvis metoden remove i din nuvarande kod? Finns ju inget där som varken plussar på eller subtraherar något från den?
Citera
2016-01-31, 19:27
  #4
Medlem
binics avatar
Citat:
Ursprungligen postat av Proton
variabeln counter ser ju aldrig ut att ändras förutom i metoden incCounter, hur skulle den kunna anta något annat värde i exempelvis metoden remove i din nuvarande kod? Finns ju inget där som varken plussar på eller subtraherar något från den?
Jag anropar incCounter via Test klassen där CustomFilter skapas, så när remove anropas vid ett senare skede så ska den redan vara uppdaterad, men det är den inte i mitt fall utan den är 0. Metoden remove anropas automatiskt av DocumentFilter när man tar bort text från JTextPane.
Citera
2016-01-31, 19:32
  #5
Moderator
Protons avatar
Citat:
Ursprungligen postat av binic
Jag anropar incCounter via Test klassen där CustomFilter skapas, så när remove anropas vid ett senare skede så ska den redan vara uppdaterad, men det är den inte i mitt fall utan den är 0. Metoden remove anropas automatiskt av DocumentFilter när man tar bort text från JTextPane.
I sådana fall bliir det att ta till debuggern. Hur som helst kommer din remove inte på egen hand att göra några uppdateringar av variabeln, det verkar vi ju vara överens om.
Citera
2016-01-31, 20:16
  #6
Medlem
binics avatar
Citat:
Ursprungligen postat av Proton
I sådana fall bliir det att ta till debuggern. Hur som helst kommer din remove inte på egen hand att göra några uppdateringar av variabeln, det verkar vi ju vara överens om.
Precis, det är något annat fel med min riktiga klass eftersom det fungerar tydligen nu när jag testade göra om allt enligt exemplet:

Kod:
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import java.awt.BorderLayout;

public class 
TestFilterExample {

    private 
JFrame frame;

    
/**
     * Launch the application.
     */
    
public static void main(String[] args) {
        
EventQueue.invokeLater(new Runnable() {
            public 
void run() {
                try {
                    
TestFilterExample window = new TestFilterExample();
                    
window.frame.setVisible(true);
                } catch (
Exception e) {
                    
e.printStackTrace();
                }
            }
        });
    }

    
/**
     * Create the application.
     */
    
public TestFilterExample() {
        
initialize();
    }

    
/**
     * Initialize the contents of the frame.
     */
    
private void initialize() {
        
frame = new JFrame();
        
frame.setBounds(100100450300);
        
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
frame.getContentPane().setLayout(new BorderLayout(00));
        
        
JTextPane textPane = new JTextPane();
        
textPane.setText("Delete any of this...");
        
frame.getContentPane().add(textPane);
        
        
int id 5;
        
        
CustomFilter customerFilter = new CustomFilter(textPane); 
        ((
AbstractDocument)(textPane.getDocument())).setDocumentFilter(customerFilter); 
        
        
//sets id of pane
        
customerFilter.setID(id);
    }
    
}

class 
CustomFilter extends DocumentFilter{
    private 
JTextPane pane;
    private 
int id;
    public 
CustomFilter(JTextPane pane) {
        
this.pane pane;
    }
    public 
void setID(int id) {
        
this.id id;
        
    }
    public 
void remove(FilterBypass fbint offsetint lengththrows BadLocationException {
        
System.out.println("Remove...");
        
System.out.println("ID of this pane is: " id);
    }

Får felsöka vidare och se vad som skiljer med ovan...
Citera
2016-08-29, 11:03
  #7
Medlem
kjellbrels avatar
Ett sent inlägg i tråden men jag tror det kan vara användbart för andra i framtiden.

Ser inte all koden här, men detta verkar vara ett klassiskt fall där olika trådar använder en och samma variabel. För att man skall vara garanterad att förändringar syns i alla trådar förrutom den som gjort ändringen så måste en variabel deklareras volatile.

private volatile int counter;

Jag gissar att remove i första fallet (som inte fungerar) anropas till följd av en GUI-händelse (info om detta saknas i beskrivningen) och sålunda kommer den att köras på javas "event dispatch thread", medans anropet till incCounter körs på programmets main-tråd, vilket då skapar synlighetsproblem trådar emellan.

I det sistnämnda fallet (som fungerar) så körs allting i samma tråd, då anropet som ändrar id också körs på UI-tråden (event dispatch thread) via anropet till EventQueue.invokeLater, så därmed uppstår inget trådproblem alls här.

Utan volatile garanteras varken att förändringar syns eller ens i vilken ordning de syns om de gör det, utifrån andra trådars perspektiv, även om det är väl defineriat inom tråden som utför dem. Så här måste det dock vara av prestandaskäl, annars skulle t ex CPU-caches och massor av kompilatoroptimeringar i princip bli helt oanvändbara.

Såg det här inlägget när det gjordes och tänkte att jag skulle svara direkt men det visade sig sannerligen inte vara enkelt att skapa ett konto på FB! Nu först efter massor av försök och många frågor via mail till FB som alla förblev obesvarade så gick en registrering igenom till sist!
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback