Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I would like to in a for cycle open a new dialog (popup) window with fields
that I will save to a database
e.g.
onPrintButton(self):
for file in files:
...
openDialogWindow() the for cycle will stop here until I press OK button with filled in values
In the opened dialog window there will be various fields (some of them already prefilled)
e.g.
date
file_name
printer_name
etc.
When I click the OK button the values will be saved to a DB (you can just print them to the console)
and the for cycle will continue where it stopped.
Could you please show me scaffolding of such functionality (which Qt classes to use etc.)?
Here is a suggestion, your QDialog can have anything you want.
class Dialog(QDialog):
accepted = pyqtSignal(dict)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.date = QDateEdit()
self.date.setDisplayFormat('MMM d, yyyy')
self.date.setDate(QDate.currentDate())
self.file_name = QLineEdit()
self.file_name.textEdited[str].connect(self.unlock)
self.printer_name = QLineEdit()
self.btn = QPushButton('OK')
self.btn.setDisabled(True)
self.btn.clicked.connect(self.ok_pressed)
form = QFormLayout(self)
form.addRow('Date', self.date)
form.addRow('*File Name', self.file_name)
form.addRow('Printer Name', self.printer_name)
form.addRow(self.btn)
def unlock(self, text):
if text:
self.btn.setEnabled(True)
else:
self.btn.setDisabled(True)
def ok_pressed(self):
values = {'Date': self.date.date(),
'File': self.file_name.text(),
'Printer': self.printer_name.text()}
self.accepted.emit(values)
self.accept()
And when you call it from the parent widget:
class Template(QWidget):
def __init__(self):
super().__init__()
dg = Dialog()
dg.accepted.connect(self.do_something)
dg.exec_()
def do_something(self, values):
print(values['File'], values['Date'], values['Printer'])
Related
I have a custom QWidget that I have embedded into a QTableWidget.
When I toggle the QCheckBoxes and modify the text in the QLineEdit widgets, the program is not able to distinguish the widgets in rows 2 and 1 from the widgets in row 0. How can I change the program so that it prints the correct row and column of the QLineEdit widget that is being edited or the Checkbox that is being toggled?
Figure 1 shows a screenshot of the program with the output after selecting the third checkbox many times in Visual Studio Code. The output is expected to read “2 0” repeatedly but instead it reads “0 0”.
Figure 2 Similarly, when I modify the text in the QLineEdit in cell 2,0 from “My Custom Text” to “Text” the program prints “Handle Cell Edited 0,0”, although it is expected to print “Handle Cell Edited 2,0 Cell 2,0 was changed to Text”.
Code:
# Much of this code is copy pasted form user: three_pineapples post on stackoverflow:
# https://stackoverflow.com/a/26311179/18914416
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, \
QApplication, QTableWidgetItem, QLineEdit, QCheckBox
from PyQt5 import QtGui
class SimpleTable(QTableWidget):
def __init__(self,window):
# Call the parent constructor
QTableWidget.__init__(self)
self.window = window
class myWidget(QWidget):
#This code is adapted paritally form a post by user sebastian at:
#https://stackoverflow.com/a/29764770/18914416
def __init__(self,parent=None):
super(myWidget,self).__init__()
self.Layout1 = QHBoxLayout()
self.item = QLineEdit("My custom text")
#https://stackabuse.com/working-with-pythons-pyqt-framework/
self.Checkbox = QCheckBox()
self.Checkbox.setCheckState(Qt.CheckState.Unchecked)
self.Layout1.addWidget(self.Checkbox)
self.Layout1.addWidget(self.item)
#https://stackoverflow.com/questions/29764395/adding-multiple-widgets-to-qtablewidget-cell-in-pyqt
self.item.home(True)
#https://www.qtcentre.org/threads/58387-Left-text-alignment-for-long-text-on-QLineEdit
self.setLayout(self.Layout1)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
layout = QHBoxLayout()
self.setLayout(layout)
self.table_widget = SimpleTable(window=self)
layout.addWidget(self.table_widget)
self.table_widget.setColumnCount(3)
self.table_widget.setHorizontalHeaderLabels(['Colour', 'Model'])
items = [('Red', 'Toyota'), ('Blue', 'RV'), ('Green', 'Beetle')]
for i in range(len(items)):
c = QTableWidgetItem(items[i][0])
m = QTableWidgetItem(items[i][1])
self.table_widget.insertRow(self.table_widget.rowCount())
self.table_widget.setItem(i, 1, c)
self.table_widget.setItem(i, 2, m)
myWidget1 = myWidget()
myWidget1.Checkbox.stateChanged.connect(self.handleButtonClicked)
myWidget1.item.editingFinished.connect(self.handle_cell_edited)
self.table_widget.setCellWidget(i,0,myWidget1)
myWidget1.Layout1.setContentsMargins(50*i+10,0,0,0)
self.show()
self.table_widget.itemChanged.connect(self.handle_cell_edited)
def handleButtonClicked(self):
#Adapted from a post by user: Andy at:
# https://stackoverflow.com/a/24149478/18914416
button = QApplication.focusWidget()
# or button = self.sender()
index = self.table_widget.indexAt(button.pos())
if index.isValid():
print(index.row(), index.column())
# I added this fuction:
def handle_cell_edited(self):
if QApplication.focusWidget() != None:
index = self.table_widget.indexAt(QApplication.focusWidget().pos())
x,y = index.column(),index.row()
if index.isValid():
print("Handle Cell Edited",index.row(), index.column())
if self.table_widget.item(y,x)!= None:
print(f"Cell {x},{y} was changed to {self.table_widget.item(y,x).text()}.")
def main():
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
main()
What I've Tried So Far:
I learned that QT has two types of widgets that can be embedded in a table; a QTableWigetItem which can be inserted into a table using setItem()(3) and Qwidgets, which can be placed into a table using setCellWidget().(4) Generally, I know that using a QTableWigetItem one can set the item.setFlags(Qt.ItemFlag.ItemIsUserCheckable)
flag to create a checkbox in the cell. (3) However, when using the QTableWigetItem, I wasn’t able to find a way to indent the checkboxes. Because giving each checkbox its own indentation level is important in the context of my program, I’ve decided to use Qwidgets instead of QTableWigetItems in the few select cells where indenting is important.
I’ve read that by creating a QItemDelegate(5)(6), you can do a lot more with setting QWidgets in boxes. However, creating a delegate seems complicated, so I’d prefer to avoid this if possible. If there is no other way to make the program register the correct cell number of the cell being edited, creating a delegate will be the next thing I look into.
For anyone who might want to experiment with QTableWigetItems in this application, here is an equivalent program that uses QTableWigetItems instead of QWidgets but doesn't permit separate indentation or editing of the text field in column 0. For either and both of these two reasons, a QTableWigetItem seems not to be usable for the checkboxes in column 0.
Less Successful Attempt using QTableWidgetItem:
#Much of this code is copy pasted form user: three_pineapples post on stackoverflow:
# https://stackoverflow.com/a/26311179/18914416
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, \
QApplication, QTableWidgetItem, QLineEdit, QCheckBox
from PyQt5 import QtGui
class SimpleTable(QTableWidget):
def __init__(self,window):
QTableWidget.__init__(self)
self.window = window
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
layout = QHBoxLayout()
self.setLayout(layout)
self.table_widget = SimpleTable(window=self)
layout.addWidget(self.table_widget)
self.table_widget.setColumnCount(3)
self.table_widget.setHorizontalHeaderLabels(['Colour', 'Model'])
items = [('Red', 'Toyota'), ('Blue', 'RV'), ('Green', 'Beetle')]
for i in range(len(items)):
c = QTableWidgetItem(items[i][0])
m = QTableWidgetItem(items[i][1])
self.table_widget.insertRow(self.table_widget.rowCount())
self.table_widget.setItem(i, 1, c)
self.table_widget.setItem(i, 2, m)
item = QTableWidgetItem("My Custom Text")
item.setFlags(Qt.ItemFlag.ItemIsUserCheckable| Qt.ItemFlag.ItemIsEnabled)
item.setCheckState(Qt.CheckState.Unchecked)
self.table_widget.setItem(i,0,item)
#https://youtu.be/DM8Ryoot7MI?t=251
self.show()
#I added this line:
self.table_widget.itemChanged.connect(self.handle_cell_edited)
def handleButtonClicked(self):
#Adapted from a post by user: Andy at:
# https://stackoverflow.com/a/24149478/18914416
button = QApplication.focusWidget()
# or button = self.sender()
index = self.table_widget.indexAt(button.pos())
if index.isValid():
print(index.row(), index.column())
# I added this fuction:
def handle_cell_edited(self):
if QApplication.focusWidget() != None:
index = self.table_widget.indexAt(QApplication.focusWidget().pos())
x,y = index.column(),index.row()
if index.isValid():
print("Handle Cell Edited",index.row(), index.column())
if self.table_widget.item(y,x)!= None:
print(f"Cell {x},{y} was changed to {self.table_widget.item(y,x).text()}.")
def main():
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
main()
Bibliography:
1.https://i.stack.imgur.com/FudE3.png
2.https://i.stack.imgur.com/C2ypp.png
3.https://youtu.be/DM8Ryoot7MI?t=251
4.https://stackoverflow.com/questions/24148968/how-to-add-multiple-qpushbuttons-to-a-qtableview/24149478#24149478
5.Creating a QItemDelegate for QWidgets, https://stackoverflow.com/a/35418141/18914416
6.Need to create a QItemDelegate to add a stylesheet to QTableWidgetItems: https://forum.qt.io/topic/13124/solved-qtablewidgetitem-set-stylesheet
The geometry of a widget is always relative to its parent.
In your first example, the problem is that the pos() returned for the widget is relative to the myWidget container, and since the vertical position is always a few pixels below the top of the parent (the layout margin), you always get the same value.
The second example has another conceptual problem: the checkbox of a checkable item is not an actual widget, so the widget you get is the table itself.
def handle_cell_edited(self):
# this will print True
print(isinstance(QApplication.focusWidget(), QTableWidget))
As explained above, the geometry is always relative to the parent, so you will actually get the position of the table relative to the window.
The solution to the first case is quite simple, as soon as you understand the relativity of coordinate systems. Note that you shall not rely on the focusWidget() (the widget might not accept focus), but actually get the sender(), which is the object that emitted the signal:
def handleButtonClicked(self):
sender = self.sender()
if not self.table_widget.isAncestorOf(sender):
return
# the widget coordinates must *always* be mapped to the viewport
# of the table, as the headers add margins
pos = sender.mapTo(self.table_widget.viewport(), QPoint())
index = self.table_widget.indexAt(pos)
if index.isValid():
print(index.row(), index.column())
In reality, this might not be that necessary, as an item delegate will suffice if the indentation is the only requirement: the solution is to properly set the option.rect() within initStyleOption() and use a custom role for the indentation:
IndentRole = Qt.UserRole + 1
class IndentDelegate(QStyledItemDelegate):
def initStyleOption(self, opt, index):
super().initStyleOption(opt, index)
indent = index.data(IndentRole)
if indent is not None:
left = min(opt.rect.right(),
opt.rect.x() + indent)
opt.rect.setLeft(left)
class SimpleTable(QTableWidget):
def __init__(self,window):
QTableWidget.__init__(self)
self.window = window
self.setItemDelegateForColumn(0, IndentDelegate(self))
class Window(QWidget):
def __init__(self):
# ...
for i in range(len(items)):
# ...
item.setData(IndentRole, 20 * i)
Using QtDesigner and PyQt5 with pyuic5 I'm setting up a FormLayout with a variable number of rows.
Each row is a custom widget created in QtDesigner, consisting of a QLabel and a QHBoxLayout containing a QLineEdit and QPushButton.
I create the row UI using
def get_data_widget(parent=None, **kwargs):
widget = QtWidgets.QWidget(parent)
dlg_ui = wgtDataRow.Ui_Form() # from the custom made widget
dlg_ui.setupUi(widget)
# recursively ensure all objectName()s are unique
rename_widget(widget, "_%s" % unique_id())
dlg_ui.label.setText(kwargs.get('name') or '')
dlg_ui.editData.setText(kwargs.get('value') or '')
return dlg_ui
The row UI is inserted in the QFormLayout in a QDialog method:
def add_data_entry_row(self, name, **kwargs):
# simplified code, but this is the bit that affects the QFormLayout
posn = kwargs.get('position', 0)
data_ui = get_data_widget(self, name=name, value=kwargs.get('value'))
self.dlg_ui.formLayout.insertRow(posn, data_ui.label, data_ui.widget)
The problem I have is that the first row of the QFormLayout is not responding to the mouse clicks.
If I insert a new row at 0 the previously unresponsive row is moved down and becomes responsive and the new (top) row unresponsive.
Can anyone throw any light on this?
While trying to generate a minimal example which had the same problem I found the cause. Basically I was making changes to the UI before executing show()
What I had (code minimised for clarity)
class Dialog(QtWidgets.QDialog):
def __init__(self, **kwargs):
super().__init__()
self.dlg_ui = Ui_Dialog()
self.dlg_ui.setupUi(self)
self.setModal(True)
self.init_ui(**kwargs) # load the UI widgets with data
self.show()
which should have been
class Dialog(QtWidgets.QDialog):
def __init__(self, **kwargs):
super().__init__()
self.dlg_ui = Ui_Dialog()
self.dlg_ui.setupUi(self)
self.setModal(True)
self.show() # excute BEFORE loading the UI
self.init_ui(**kwargs) # load the UI widgets with data
This question already has an answer here:
Adding items to a QTableView within QCalendarWidget
(1 answer)
Closed 3 years ago.
I found a mouseDoubleClickEvent in QCalendarWidget, but it doesn't work on date cell. Is there a good solution?
[signal]void QCalendarWidget::activated(const QDate &date
This signal is emitted whenever the user presses the Return or Enter key or double-clicks a date in the calendar widget.
from PyQt5 import QtWidgets, QtCore
def activatedDate(date):
print(date)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
cal = QtWidgets.QCalendarWidget()
cal.activated.connect(activatedDate) # <---
fn = cal.font()
fn.setPointSize(20)
cal.setFont(fn)
prev_button = cal.findChild(QtWidgets.QToolButton, "qt_calendar_prevmonth")
next_button = cal.findChild(QtWidgets.QToolButton, "qt_calendar_nextmonth")
for btn in (prev_button, next_button):
btn.setIconSize(QtCore.QSize(40, 40))
cal.resize(640, 480)
cal.show()
sys.exit(app.exec_())
I have an application which uses a QTableView/QAbstractTableModel combination. For the view, I've defined a Delegate which displays an image (a QPixmap, loaded from an image file) in one column of the table view.
Basically, the problem is that when a cell in the column with the Delegate is selected, sometimes the background shows and sometimes it doesn't.
Here is what I've discovered by experimentation so far, and I can't make much sense of it:
I have this relatively short test program:
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
# ------------------------------------------------------------------------------
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data = [[]], headers = None, parent = None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.__data = data
def rowCount(self, parent):
return len(self.__data)
def columnCount(self, parent):
return len(self.__data[0])
def data(self, index, role):
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
value = self.__data[row][column]
return value
def flags(self, index):
return QtCore.Qt.ItemIsEnabled|QtCore.Qt.ItemIsEditable|QtCore.Qt.ItemIsSelectable
# ------------------------------------------------------------------------------
class Delegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
if (index.column() == 0):
image = QtGui.QImage('open.png')
pixmap = QtGui.QPixmap.fromImage(image)
x = option.rect.center().x() - pixmap.rect().width() / 2
y = option.rect.center().y() - pixmap.rect().height() / 2
painter.drawPixmap(x, y, pixmap)
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
tableView = QtWidgets.QTableView()
tableView.setItemDelegateForColumn(0, Delegate())
tableView.resize(550, 160)
tableView.show()
rowCount = 3
columnCount = 4
data = [
[i for i in range(columnCount)]
for j in range(rowCount)
]
model = TableModel(data)
tableView.setModel(model)
sys.exit(app.exec_())
When I specify app.setStyle('fusion') in __main__, I get what I would expect: When a cell in the column with the Delegate is selected, the cell background is blue and the image appears in front of it:
However, if I change to app.setStyle('windows'), even though in general it uses the same blue background for selected cells, when I move to a cell in the first column, the background disappears:
(You can't obviously see it, but the same cell is selected as in the first example).
That's just a piece of test code, which I don't completely understand.
In the actual application I'm writing, I am using Qt Designer to create the UI. Even though I specify app.setStyle('fusion'), the table has entirely different styling, with a different appearance to the background of a selected cell:
I can't for the life of me figure out where it is picking up the different style. It must come from Qt Designer somehow, but I've looked at the .py file Qt Designer creates, and I can't find it.
This style (wherever it comes from) seems to suffer from the same problem as the windows style. In the image above, there is no Delegate in use. The cell in row 2/column 2 is selected, and the background shows.
But if I add a Delegate to display a QPixmap in column 2, then the background does not show when the cell is selected:
(It's selected; take my word for it).
I thought maybe it was the case that once you use a Delegate to display an image, you could no longer get a background in the selected cell. But you obviously can. It works in one case, just not the others.
If anyone can shed light on this, I'd appreciate it. (I realize this is long; thanks for sticking with me).
I've been fiddling around with this issue more, and I've learned some things about my original question. In retrospect, I think it was not as clear as it could have been (or maybe I just understand it all a bit better).
For starters, I never should have referred to cells as being "selected". In fact, I don't even have the Qt.ItemIsSelectable flag set for any of the cells in the view. What I really have been trying to do is control the background of a cell when it is active (for lack of a better word) -- meaning it is the cell where the cursor is currently positioned.
This can be done by overriding initStyleOption() in the Delegate. My original test code is modified as shown below:
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
# ------------------------------------------------------------------------------
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data = [[]], headers = None, parent = None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.__data = data
def rowCount(self, parent):
return len(self.__data)
def columnCount(self, parent):
return len(self.__data[0])
def data(self, index, role):
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
value = self.__data[row][column]
return value
if role == QtCore.Qt.BackgroundRole:
return QtGui.QBrush(QtGui.QColor(255, 255, 255))
def flags(self, index):
return QtCore.Qt.ItemIsEnabled|QtCore.Qt.ItemIsEditable
# ------------------------------------------------------------------------------
class TableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super().__init__(parent)
# ------------------------------------------------------------------------------
class Delegate(QtWidgets.QStyledItemDelegate):
# <Modification>
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
if (
index.row() == tableView.currentIndex().row() and
index.column() == tableView.currentIndex().column()
):
option.backgroundBrush = QtGui.QBrush(QtGui.QColor(232, 244, 252))
def paint(self, painter, option, index):
if (index.column() == 0):
# <Modification>
if (
index.row() == tableView.currentIndex().row() and
index.column() == tableView.currentIndex().column()
):
self.initStyleOption(option, index)
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(option.backgroundBrush)
painter.drawRect(option.rect)
image = QtGui.QImage('open.png')
pixmap = QtGui.QPixmap.fromImage(image)
x = option.rect.center().x() - pixmap.rect().width() / 2
y = option.rect.center().y() - pixmap.rect().height() / 2
painter.drawPixmap(x, y, pixmap)
else:
super().paint(painter, option, index)
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
tableView = TableView()
tableView.resize(550, 160)
tableView.setItemDelegate(Delegate())
tableView.show()
rowCount = 3
columnCount = 4
data = [
[i for i in range(columnCount)]
for j in range(rowCount)
]
model = TableModel(data)
tableView.setModel(model)
sys.exit(app.exec_())
initStyleOption() sets the background brush for a cell when it is active (current). But as I bemoaned before, this doesn't occur in the first column, which has a Delegate with a custom paint() method that displays a pixmap. So paint() must also take responsibility for setting the background for cells in that column when they are active. It uses the same backgroundBrush that initStyleOption() set.
The result is very nearly what I'm shooting for. The only fly in the ointment is that there is still clearly additional styling going on, that affects all the cells in the view except those in column 1 with the custom Delegate. So they don't look quite exactly alike when active:
(It's subtle, but there's a bit of a gradient to the background of the cell in column 2, which is absent in column 1).
I know now that there are style 'factories' that apply a widget-wide style. Since I'm using Fusion, that is evidently where the extra styling is coming from.
So now my question is -- where is that styling defined, and do I have any control over it? If I could see it, I could make my custom background style match it. Better yet, if I could modify it, I could make it match mine.
I had the same problem with my own tool today. I think your issue is the same as this other question. In short, you just need to call super in paint before doing any of your extra work. When I added super to my own code, selections worked again as expected in the delegate.
class Delegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
super().paint(painter, option, index)
if (index.column() == 0):
image = QtGui.QImage('open.png')
pixmap = QtGui.QPixmap.fromImage(image)
x = option.rect.center().x() - pixmap.rect().width() / 2
y = option.rect.center().y() - pixmap.rect().height() / 2
painter.drawPixmap(x, y, pixmap)
(FWIW I haven't tested the code above. But it should work).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Function() to define Model
with tf.variable_scope('RNNLM') as scope:
self.initial_state = tf.zeros(shape = (self.config.batch_size, self.config.hidden_size) )
H = tf.get_variable('H',(self.config.hidden_size, self.config.hidden_size),tf.float32,init)
I = tf.get_variable('I',(self.config.embed_size, self.config.hidden_size),tf.float32,init)
b_1= tf.get_variable('bias-1',(1,self.config.hidden_size),tf.float32,init)
U = tf.get_variable('U',(self.config.hidden_size, len(self.vocab)),tf.float32,init)
b_2= tf.get_variable('bias-2',(1,len(self.vocab)),tf.float32,init)
with tf.variable_scope('RNNLM') as scope:
scope.reuse_variables()
self.current_state = self.initial_state
H = tf.get_variable('H',(self.config.hidden_size, self.config.hidden_size),tf.float32,init)
I = tf.get_variable('I',(self.config.embed_size, self.config.hidden_size),tf.float32,init)
b_1= tf.get_variable('bias-1',(1,self.config.hidden_size),tf.float32,init)
U = tf.get_variable('U',(self.config.hidden_size, len(self.vocab)),tf.float32,init)
b_2= tf.get_variable('bias-2',(1,len(self.vocab)),tf.float32,init)
for t in xrange(self.config.num_steps):
self.current_state = tf.sigmoid(tf.matmul(self.current_state,H)+tf.matmul(inputs[t],I)+b_1)
rnn_outputs.append(self.current_state)
self.final_state = rnn_outputs[-1]
function( loss ) to define the training operation
train_op = tf.train.AdamOptimizer(self.config.lr).minimize(loss)
ValueError: Variable RNNLM/RNNLM/RNNLM/Variable_1/Adadelta/ does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=None in VarScope?
You have accidentally put the declare of train_op into the scope RNNLM which is in 'variable share' mode by calling scope.reuse_variables(). Move it out of the scope, and you will get your code run.